TL; DR
JSONP là một thủ thuật cũ được phát minh để vượt qua giới hạn bảo mật cấm chúng tôi lấy dữ liệu JSON từ một máy chủ khác ( nguồn gốc khác * ).
Thủ thuật này hoạt động bằng cách sử dụng <script>
thẻ yêu cầu JSON từ nơi đó, ví dụ : { "user":"Smith" }
, nhưng được bao bọc trong một hàm, JSONP thực tế ("JSON với Padding"):
peopleDataJSONP({"user":"Smith"})
Nhận nó dưới dạng này cho phép chúng tôi sử dụng dữ liệu trong peopleDataJSONP
chức năng của mình. JSONP là một thực tiễn xấu , không sử dụng nó (đọc bên dưới)
Vấn đề
Giả sử chúng tôi đang điều hướng ourweb.com
và chúng tôi muốn lấy dữ liệu JSON (hoặc bất kỳ dữ liệu thô nào thực sự) từ đó anotherweb.com
. Nếu chúng tôi sử dụng yêu cầu GET (như XMLHttpRequest
, một fetch
cuộc gọi $.ajax
, v.v.), trình duyệt của chúng tôi sẽ cho chúng tôi biết rằng nó không được phép với lỗi xấu này:
Làm thế nào để có được dữ liệu chúng ta muốn? Chà, <script>
các thẻ không bị hạn chế toàn bộ máy chủ (nguồn gốc *) này! Đó là lý do tại sao chúng tôi có thể tải thư viện như jQuery hoặc Google Maps từ bất kỳ máy chủ nào, chẳng hạn như CDN, mà không có bất kỳ lỗi nào.
Điểm quan trọng : nếu bạn nghĩ về nó, các thư viện đó là mã JS thực tế, có thể chạy được (thường là một hàm lớn với tất cả logic bên trong). Nhưng dữ liệu thô? Dữ liệu JSON không phải là mã . Không có gì để chạy; nó chỉ là dữ liệu đơn giản.
Do đó, không có cách nào để xử lý hoặc thao túng dữ liệu quý giá của chúng tôi. Trình duyệt sẽ tải xuống dữ liệu được chỉ ra bởi <script>
thẻ của chúng tôi và khi xử lý, nó sẽ khiếu nại đúng:
wtf này là {"user":"Smith"}
crap chúng tôi tải? Đó không phải là mã. Tôi không thể tính toán, lỗi cú pháp!
Bản hack JSONP
Cách cũ / hacky để sử dụng dữ liệu đó? Chúng tôi cần máy chủ đó gửi nó với một số logic, vì vậy khi được tải, mã của bạn trong trình duyệt sẽ có thể sử dụng dữ liệu nói trên. Vì vậy, máy chủ nước ngoài gửi cho chúng tôi dữ liệu JSON bên trong hàm JS. Dữ liệu được thiết lập làm đầu vào của chức năng đó. Nó trông như thế này:
peopleDataJSONP({"user":"Smith"})
mà làm cho nó mã JS trình duyệt của chúng tôi sẽ phân tích mà không phàn nàn! Chính xác như nó làm với thư viện jQuery. Bây giờ, để có được nó như thế, máy khách "yêu cầu" máy chủ thân thiện với JSONP cho nó, thường được thực hiện như thế này:
<script src="https://anotherweb.com/api/data-from-people.json?myCallback=peopleDataJSONP"></script>
Trình duyệt của chúng tôi sẽ nhận được JSONP với tên hàm đó, do đó chúng tôi cần một hàm có cùng tên trong mã của chúng tôi, như sau:
const peopleDataJSONP = function(data){
alert(data.user); // "Smith"
}
Hoặc như thế này, kết quả tương tự:
function peopleDataJSONP(data){
alert(data.user); // "Smith"
}
Trình duyệt sẽ tải xuống JSONP và chạy nó, gọi hàm của chúng ta , trong đó đối số data
sẽ là JSON của chúng ta. Bây giờ chúng tôi có thể làm với dữ liệu của mình bất cứ điều gì chúng tôi muốn.
Không sử dụng JSONP, sử dụng CORS
JSONP là một hack nhiều trang web với một vài nhược điểm:
- Chúng tôi chỉ có thể thực hiện các yêu cầu NHẬN
- Vì đó là một yêu cầu GET được kích hoạt bởi một thẻ script đơn giản, chúng tôi không nhận được các lỗi hữu ích hoặc thông tin tiến trình
- Ngoài ra còn có một số lo ngại về bảo mật, như chạy trong mã JS khách hàng của bạn có thể bị thay đổi thành tải trọng độc hại
- Nó chỉ giải quyết vấn đề với dữ liệu JSON, nhưng chính sách bảo mật cùng nguồn gốc áp dụng cho các dữ liệu khác (WebFonts, hình ảnh / video được vẽ bằng drawImage () ...)
- Nó không phải là rất thanh lịch cũng không thể đọc được.
Điều đáng nói là ngày nay không cần sử dụng nó .
JSONP là mẹo để lấy dữ liệu JSON từ một máy chủ khác, nhưng chúng tôi sẽ vi phạm nguyên tắc bảo mật tương tự (Cùng nguồn gốc) nếu chúng tôi cần các loại công cụ chéo trang khác.
Bạn nên đọc về CORS ở đây , nhưng ý chính của nó là:
Chia sẻ tài nguyên nguồn gốc chéo (CORS) là một cơ chế sử dụng các tiêu đề HTTP bổ sung để báo cho các trình duyệt cung cấp cho ứng dụng web chạy ở một nguồn gốc, truy cập vào các tài nguyên được chọn từ một nguồn gốc khác. Một ứng dụng web thực hiện một yêu cầu HTTP có nguồn gốc chéo khi nó yêu cầu một tài nguyên có nguồn gốc khác (miền, giao thức hoặc cổng) từ chính nó.
* nguồn gốc được xác định bởi 3 điều: giao thức , cổng và máy chủ . Vì vậy, ví dụ, https://web.com
là một nguồn gốc khác với http://web.com
(giao thức khác nhau) và https://web.com:8081
(cổng khác nhau) và rõ ràng https://thatotherweb.net
(máy chủ khác nhau)