TL; DR
JSONP - старий трюк, придуманий для обходу обмеження безпеки, який забороняє нам отримувати дані JSON з іншого сервера (різного походження * ).
Трюк працює, використовуючи <script>
тег, який запитує JSON з цього місця, наприклад:, { "user":"Smith" }
але загорнутий у функцію, власне JSONP ("JSON with Padding"):
peopleDataJSONP({"user":"Smith"})
Отримання в цій формі дозволяє нам використовувати дані в межах нашої peopleDataJSONP
функції. JSONP - це погана практика , не використовуйте її (читайте нижче)
Проблема
Скажімо, ми переходимо ourweb.com
, і ми хочемо отримати дані JSON (або будь-які необроблені дані) anotherweb.com
. Якби ми використовували GET-запит (наприклад XMLHttpRequest
, fetch
дзвінок $.ajax
тощо), наш браузер сказав би нам, що це не допускається з цією потворною помилкою:
Як отримати потрібні нам дані? Ну, <script>
теги не підпадають під обмеження всього цього сервера (походження *)! Ось чому ми можемо завантажувати бібліотеку на зразок jQuery або Google Maps з будь-якого сервера, наприклад CDN, без помилок.
Важливий момент : якщо ви подумаєте про це, ці бібліотеки є фактичним, керуючим кодом JS (зазвичай це масивна функція з усією логікою всередині). Але необроблені дані? Дані JSON не є кодом . Нічого не бігти; це просто прості дані.
Таким чином, немає ніякого способу обробляти наші цінні дані. Веб-браузер завантажить дані, на які вказує наш <script>
тег, і при обробці він справедливо скаржиться:
wtf це {"user":"Smith"}
лайно, яке ми завантажили? Це не код. Я не можу обчислити, синтаксична помилка!
Злом JSONP
Старий / хакітський спосіб використання цих даних? Нам потрібен той сервер, щоб надіслати його з певною логікою, тому коли він завантажиться, ваш код у браузері зможе використовувати вказані дані. Таким чином, іноземний сервер передає нам дані JSON всередині функції JS. Самі дані встановлюються як вхід цієї функції. Це виглядає приблизно так:
peopleDataJSONP({"user":"Smith"})
що робить його JS-кодом наш браузер буде розбирати без нарікань! Так само, як і в бібліотеці jQuery. Тепер, щоб зробити це таким чином, клієнт "запитує" для нього зручний сервер JSONP, як правило, робиться так:
<script src="https://anotherweb.com/api/data-from-people.json?myCallback=peopleDataJSONP"></script>
Наш браузер отримає JSONP з цією назвою функції, отже, нам потрібна функція з тим самим іменем у нашому коді, як це:
const peopleDataJSONP = function(data){
alert(data.user); // "Smith"
}
Або так, такий же результат:
function peopleDataJSONP(data){
alert(data.user); // "Smith"
}
Браузер завантажить JSONP і запустить його, що викликає нашу функцію , де аргументом data
буде наш JSON. Тепер ми можемо робити з нашими даними все, що завгодно.
Не використовуйте JSONP, використовуйте CORS
JSONP - це хек-сайти з кількома недоліками:
- Ми можемо виконувати лише GET запити
- Оскільки це запит GET, ініційований простим тегом скрипту, ми не отримуємо корисних помилок або інформації про прогрес
- Існують також деякі проблеми безпеки, наприклад, запуск у вашому JS-коді клієнта, який може бути змінений на шкідливий навантаження
- Він вирішує проблему лише з даними JSON, але політика безпеки Same-Origin застосовується і до інших даних (WebFonts, зображення / відео, намальовані малюнком drawImage () ...)
- Це не дуже елегантно і не читабельно.
Вигода полягає в тому, що зараз не потрібно використовувати його .
JSONP - хитрість отримати дані JSON з іншого сервера, але ми порушимо той же принцип безпеки (Same-Origin), якщо нам потрібні інші види крос-сайтів.
Ви повинні прочитати про CORS тут , але суть його:
Перехресне походження ресурсів (CORS) - це механізм, який використовує додаткові заголовки HTTP, щоб повідомити браузерам надати веб-додатку, що працює з одним джерелом, доступ до вибраних ресурсів з іншого походження. Веб-додаток виконує запит HTTP-походження, коли він запитує ресурс, який має інше походження (домен, протокол або порт) від власного.
* походження визначається трьома речами: протоколом , портом і хостом . Так, наприклад, https://web.com
має інше походження, ніж http://web.com
(різний протокол) і https://web.com:8081
(інший порт) і очевидно https://thatotherweb.net
(інший хост)