Может ли кто-нибудь объяснить, что такое JSONP, с точки зрения непрофессионала?

Я знаю, что JSONP JSON с заполнением.

Я понимаю, что такое JSON и как его использовать с jQuery.getJSON(). Однако я не понимаю концепцию callback при введении JSONP.

Может ли кто-нибудь объяснить мне, как это работает?


person Someone    schedule 01.10.2010    source источник
comment
Потенциально полезно: stackoverflow.com/questions/2067472/please-explain-jsonp   -  person Matt    schedule 01.10.2010


Ответы (4)


Предисловие:

Этому ответу больше шести лет. Хотя концепции и применение JSONP не изменились (т. Е. Детали ответа все еще действительны), вам следует старайтесь использовать CORS там, где это возможно (например, ваш сервер или API поддерживает его, а поддержка браузера адекватна), поскольку JSONP имеет неотъемлемые риски безопасности.


JSONP (JSON с заполнением) - это метод, обычно используемый для обхода междоменных политик в веб-браузерах. (Вам не разрешено делать AJAX-запросы к веб-странице, которую браузер воспринимает как находящуюся на другом сервере.)

JSON и JSONP по-разному ведут себя на клиенте и сервере. Запросы JSONP не отправляются с использованием XMLHTTPRequest и связанных методов браузера. Вместо этого создается тег <script>, источником которого является целевой URL. Затем этот тег скрипта добавляется в DOM (обычно внутри элемента <head>).

Запрос JSON:

var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    // success
  };
};

xhr.open("GET", "somewhere.php", true);
xhr.send();

Запрос JSONP:

var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';

document.getElementsByTagName("head")[0].appendChild(tag);

Разница между ответом JSON и ответом JSONP заключается в том, что объект ответа JSONP передается в качестве аргумента функции обратного вызова.

JSON:

{ "bar": "baz" }

JSONP:

foo( { "bar": "baz" } );

Вот почему вы видите запросы JSONP, содержащие параметр callback, чтобы сервер знал имя функции, которая оборачивает ответ.

Эта функция должна существовать в глобальной области в момент, когда тег <script> оценивается браузером (после завершения запроса).


Еще одно различие между обработкой ответа JSON и ответа JSONP, о котором следует помнить, заключается в том, что любые ошибки синтаксического анализа в ответе JSON могут быть обнаружены путем заключения попытки оценить responseText в операторе try / catch. Из-за природы ответа JSONP ошибки синтаксического анализа в ответе вызовут неуловимую ошибку синтаксического анализа JavaScript.

Оба формата могут реализовывать ошибки тайм-аута, устанавливая тайм-аут перед инициированием запроса и очищая тайм-аут в обработчике ответа.


Использование jQuery

Полезность использования jQuery для выполнения запросов JSONP заключается в том, что jQuery выполняет вся работа за вас в фоновом режиме.

По умолчанию jQuery требует, чтобы вы включили &callback=? в URL-адрес вашего AJAX-запроса. jQuery примет указанную вами функцию success, присвоит ей уникальное имя и опубликует ее в глобальной области. Затем он заменит вопросительный знак ? в &callback=? присвоенным им именем.


Сопоставимые реализации JSON / JSONP

Следующее предполагает объект ответа { "bar" : "baz" }

JSON:

var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    document.getElementById("output").innerHTML = eval('(' + this.responseText + ')').bar;
  };
};

xhr.open("GET", "somewhere.php", true);
xhr.send();

JSONP:

function foo(response) {
  document.getElementById("output").innerHTML = response.bar;
};

var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';

document.getElementsByTagName("head")[0].appendChild(tag);
person Matt    schedule 01.10.2010
comment
Это объяснение принадлежит музею! ВСЕ ОПОРЫ для @Matt на лучшей работе по объяснению jsonp. Серьезно, потратил целый день на чтение, и это было, безусловно, лучшим. - person Eduardo La Hoz Miranda; 13.03.2014
comment
Отличное объяснение непрофессионала. Re: Вот почему вы видите запросы JSONP, содержащие параметр обратного вызова; так что серверу известно имя функции, которая будет оборачивать ответ. - Я просто хотел добавить, что серверу даже не нужно возвращать объект JSON, переданный функции обратного вызова - он может возвращать любой произвольный код JavaScript (пример: jsontest.com/#code). Возможности огромны. - person thdoan; 14.04.2015
comment
По сути, не только можно запрашивать данные с внешнего веб-сервера, теперь внешний веб-сервер может автоматически вставлять любой скрипт на веб-страницу. а у клиента не было возможности даже взглянуть на код перед его выполнением! Долгий путь назад от замены JSON.parse на eval в целях безопасности. - person Levi Haskell; 30.12.2015
comment
Я все еще не уверен, в чем смысл JSONP. Если сервер может добавить заполнение, он также может поместить заголовок Access-Control-Allow-Origin в ответ? - person Andrew Savinykh; 28.04.2016
comment
@AndrewSavinykh: Вы правы. Однако помимо сервера, добавляющего заголовки Access-Control-Allow-Origin, вам также понадобятся браузеры, которые иметь поддержку CORS. IE7 не поддерживался, а IE8 и 9 имели поддержку за пределами XMLHttpRequest (обратите внимание, что этот ответ относится к 2010 году!). Учитывая, что эти браузеры больше не поддерживаются Microsoft, а в целях безопасности JSONP, по возможности следует использовать CORS (где это возможно). - person Matt; 28.04.2016
comment
Обратите внимание, что это работает только с javascript, а не, скажем, text/ng-template. - person Claudiu; 20.06.2016
comment
@Matt Меня смутило одно: когда вы сказали, что запросы JSONP не отправляются с использованием XMLHTTPRequest ... Тогда как ‹script› отправляет запрос на получение, если он не использует XMLHTTPRequest? - person Qiulang; 06.07.2020

Скажем, у вас есть URL-адрес, по которому вы получили данные в формате JSON, например:

{'field': 'value'}

... и у вас был аналогичный URL-адрес, за исключением того, что он использовал JSONP, которому вы передали имя функции обратного вызова myCallback (обычно это делается путем передачи ей параметра запроса с именем callback, например http://example.com/dataSource?callback=myCallback). Затем он вернется:

myCallback({'field':'value'})

... который является не просто объектом, а на самом деле кодом, который может быть выполнен. Поэтому, если вы определите функцию myFunction в другом месте своей страницы и выполните этот сценарий, он будет вызываться с данными из URL-адреса.

Самое интересное в этом: вы можете создать тег скрипта и использовать свой URL (с параметром callback) в качестве атрибута src, и браузер запустит его. Это означает, что вы можете обойти политику безопасности «одинакового происхождения» (поскольку браузеры позволяют запускать теги сценария из источников, отличных от домена страницы).

Это то, что делает jQuery, когда вы делаете запрос ajax (используя .ajax с 'jsonp' в качестве значение свойства dataType). Например.

$.ajax({
  url: 'http://example.com/datasource',
  dataType: 'jsonp',
  success: function(data) {
    // your code to handle data here
  }
});

Здесь jQuery заботится об имени функции обратного вызова и параметре запроса, делая API идентичным другим вызовам ajax. Но в отличие от других типов запросов ajax, как уже упоминалось, вы не ограничены получением данных из того же источника, что и ваша страница.

person sje397    schedule 01.10.2010
comment
Ну вот наконец и стало ясно;) - person Mirko; 20.06.2013
comment
Наконец, тот, кто умеет передавать информацию. Спасибо @ sje397 - person philip oghenerobo balogun; 25.05.2017

JSONP - это способ обойти политику одинакового происхождения браузера. Как? Нравится:

введите описание изображения здесь

Цель здесь - сделать запрос к otherdomain.com и alert имени в ответе. Обычно мы делаем запрос AJAX:

$.get('otherdomain.com', function (response) {
  var name = response.name;
  alert(name);
});

Однако, поскольку запрос отправляется в другой домен, это не сработает.

Однако мы можем сделать запрос, используя тег <script>. Оба <script src="otherdomain.com"></script> и $.get('otherdomain.com') приведут к тому, что будет сделан один и тот же запрос:

GET otherdomain.com

В: Но если мы используем тег <script>, как мы можем получить доступ к ответу? Нам нужно получить к нему доступ, если мы хотим alert это сделать.

A: Мы не можем. Но вот что мы могли бы сделать - определить функцию, которая использует ответ, а затем сказать серверу, чтобы он ответил с помощью JavaScript, который вызывает нашу функцию с ответом в качестве аргумента.

В: Но что, если сервер не сделает этого за нас, а только захочет вернуть нам JSON?

A: Тогда мы не сможем его использовать. JSONP требует взаимодействия сервера.

В: Использование тега <script> уродливо.

О: Библиотеки, такие как jQuery, делают его лучше. Бывший:

$.ajax({
    url: "http://otherdomain.com",
    jsonp: "callback",
    dataType: "jsonp",
    success: function( response ) {
        console.log( response );
    }
});

Он работает, динамически создавая элемент DOM тега <script>.

В: Теги <script> отправляют только запросы GET - что, если мы хотим сделать запрос POST?

О: Тогда JSONP у нас работать не будет.

В: Ничего страшного, я просто хочу сделать запрос GET. JSONP великолепен, и я собираюсь его использовать - спасибо!

A: На самом деле, это не так уж и здорово. Это действительно просто взлом. И это не самое безопасное для использования. Теперь, когда доступен CORS, вы должны использовать его, когда это возможно.

person Adam Zerner    schedule 07.05.2017
comment
эта диаграмма взаимодействия очень помогает, спасибо! - person Tarocco; 29.09.2017

Я нашел полезную статью, которая также объясняет тему довольно ясно и простым языком. Ссылка - JSONP.

Некоторые из важных моментов:

  1. JSONP предшествует CORS.
  2. Это псевдостандартный способ получения данных из другого домена,
  3. Он имеет ограниченные функции CORS (только метод GET)

Работа выглядит следующим образом:

  1. <script src="url?callback=function_name"> включен в HTML-код
  2. Когда выполняется шаг 1, он воспринимает функцию с тем же именем (как указано в параметре url) в качестве ответа.
  3. Если функция с заданным именем существует в коде, она будет выполнена с данными, если таковые имеются, возвращенными в качестве аргумента этой функции.
person Harshit Garg    schedule 29.06.2017