TL; DR
JSONP to stara sztuczka wymyślona w celu ominięcia ograniczenia bezpieczeństwa, które zabrania nam pobierania danych JSON z innego serwera (innego pochodzenia * ).
Sztuczka działa przy użyciu <script>
znacznika, który prosi o JSON z tego miejsca, np .: { "user":"Smith" }
ale zawinięty w funkcję, rzeczywisty JSONP („JSON z Paddingiem”):
peopleDataJSONP({"user":"Smith"})
Otrzymanie go w tym formularzu umożliwia nam wykorzystanie danych w ramach naszej peopleDataJSONP
funkcji. JSONP to zła praktyka , nie używaj jej (czytaj poniżej)
Problem
Powiedzmy, że nawigujemy dalej ourweb.com
i chcemy uzyskać dane JSON (lub dowolne surowe dane) anotherweb.com
. Gdybyśmy byli w użyciu żądania GET (jak XMLHttpRequest
, na fetch
rozmowy $.ajax
, itd.), Nasza przeglądarka powie nam, że nie wolno z tego brzydkiego błędu:
Jak zdobyć potrzebne nam dane? Cóż, <script>
tagi nie podlegają temu ograniczeniu do całego serwera (pochodzenie *)! Właśnie dlatego możemy załadować bibliotekę taką jak jQuery lub Mapy Google z dowolnego serwera, takiego jak CDN, bez żadnych błędów.
Ważna uwaga : jeśli się nad tym zastanowić, te biblioteki są rzeczywistym, działającym kodem JS (zwykle jest to ogromna funkcja z całą logiką wewnątrz). Ale surowe dane? Dane JSON nie są kodem . Nie ma co biegać; to tylko zwykłe dane.
Dlatego nie ma sposobu, aby obchodzić się z naszymi cennymi danymi lub nimi manipulować. Przeglądarka pobierze dane wskazane przez nasz <script>
tag, a podczas przetwarzania słusznie narzeka:
wtf, czy to {"user":"Smith"}
badziewie, które załadowaliśmy? To nie jest kod. Nie mogę obliczyć, błąd składniowy!
Hack JSONP
Stary / hacky sposób na wykorzystanie tych danych? Potrzebujemy tego serwera, aby wysłać go z pewną logiką, więc gdy zostanie załadowany, twój kod w przeglądarce będzie mógł używać tych danych. Więc obcy serwer wysyła nam dane JSON wewnątrz funkcji JS. Same dane są konfigurowane jako dane wejściowe tej funkcji. To wygląda tak:
peopleDataJSONP({"user":"Smith"})
co sprawia, że kod JS nasza przeglądarka będzie analizować bez narzekań! Dokładnie tak jak w przypadku biblioteki jQuery. Teraz, aby uzyskać to w ten sposób, klient „prosi” o to serwer przyjazny dla JSONP, zwykle tak:
<script src="https://anotherweb.com/api/data-from-people.json?myCallback=peopleDataJSONP"></script>
Nasza przeglądarka otrzyma JSONP o tej nazwie funkcji, dlatego potrzebujemy funkcji o tej samej nazwie w naszym kodzie, jak poniżej:
const peopleDataJSONP = function(data){
alert(data.user); // "Smith"
}
Lub w ten sposób ten sam wynik:
function peopleDataJSONP(data){
alert(data.user); // "Smith"
}
Przeglądarka pobierze JSONP i uruchomi go, który wywołuje naszą funkcję , gdzie argumentem data
będzie nasz JSON. Możemy teraz robić z naszymi danymi, co tylko chcemy.
Nie używaj JSONP, używaj CORS
JSONP to hack między witrynami z kilkoma wadami:
- Możemy wykonywać tylko żądania GET
- Ponieważ jest to żądanie GET wywołane przez prosty tag skryptu, nie otrzymujemy pomocnych błędów ani informacji o postępie
- Istnieją również pewne obawy dotyczące bezpieczeństwa, takie jak uruchomienie w kodzie JS klienta, który można zmienić na złośliwy ładunek
- Rozwiązuje tylko problem z danymi JSON, ale zasady bezpieczeństwa Same-Origin dotyczą innych danych (WebFonts, obrazy / wideo rysowane za pomocą drawImage () ...)
- Nie jest zbyt elegancki ani czytelny.
Na wynos nie ma potrzeby korzystania z niego w dzisiejszych czasach .
JSONP jest sztuczką, aby uzyskać dane JSON z innego serwera, ale naruszymy tę samą zasadę bezpieczeństwa (Same-Origin), jeśli będziemy potrzebować innego rodzaju rzeczy między witrynami.
Powinieneś przeczytać o CORS tutaj , ale jego sedno brzmi:
Cross-Origin Resource Sharing (CORS) to mechanizm, który wykorzystuje dodatkowe nagłówki HTTP, aby poinformować przeglądarki, aby dały aplikacji internetowej działającej na jednym źródle dostęp do wybranych zasobów z innego źródła. Aplikacja internetowa wykonuje żądanie HTTP z innego źródła, gdy żąda zasobu, który ma inne pochodzenie (domenę, protokół lub port) niż własny.
* pochodzenie jest definiowane przez 3 rzeczy: protokół , port i host . Na przykład, https://web.com
ma inne pochodzenie niż http://web.com
(inny protokół) i https://web.com:8081
(inny port) i oczywiście https://thatotherweb.net
(inny host)