Я понимаю JSON, но не JSONP. Документ Википедии о JSON является (был) лучшим результатом поиска для JSONP. Это говорит это:

JSONP или «JSON with padding» - это расширение JSON, префикс которого указан в качестве входного аргумента самого вызова.

А? Какой звонок? Это не имеет никакого смысла для меня. JSON - это формат данных. Там нет звонка.

2-й результат поиска от какого-то парня по имени Реми, который пишет это о JSONP:

JSONP - это инъекция тега сценария, передающая ответ от сервера в указанную пользователем функцию.

Я могу это понять, но это все равно не имеет никакого смысла.


Так что же такое JSONP? Почему он был создан (какую проблему он решает)? И зачем мне это использовать?


Приложение . Я только что создал новую страницу для JSONP в Википедии. ; теперь он содержит четкое и подробное описание JSONP, основанное на ответе jvenema.

2225
Cheeso 14 Янв 2010 в 23:53

10 ответов

Лучший ответ

Это на самом деле не так уж сложно ...

Предположим, вы находитесь в домене example.com и хотите отправить запрос в домен example.net . Для этого вам необходимо пересечь доменные границы, что является нет-нет в большинстве браузерных стран.

Единственный элемент, который обходит это ограничение, это теги <script>. Когда вы используете тег сценария, ограничение домена игнорируется, но при нормальных обстоятельствах вы ничего не можете сделать с результатами, сценарий просто оценивается.

Введите JSONP . Когда вы отправляете запрос на сервер с поддержкой JSONP, вы передаете специальный параметр, который немного сообщает серверу о вашей странице. Таким образом, сервер может обернуть свой ответ так, как ваша страница может обработать.

Например, скажем, сервер ожидает параметр callback , чтобы включить его возможности JSONP. Тогда ваш запрос будет выглядеть так:

http://www.example.net/sample.aspx?callback=mycallback

Без JSONP это может вернуть некоторый базовый объект JavaScript, например так:

{ foo: 'bar' }

Однако в JSONP, когда сервер получает параметр «обратного вызова», он оборачивает результат немного по-другому, возвращая что-то вроде этого:

mycallback({ foo: 'bar' });

Как видите, теперь он будет вызывать указанный вами метод. Итак, на вашей странице вы определяете функцию обратного вызова:

mycallback = function(data){
  alert(data.foo);
};

И теперь, когда скрипт загружен, он будет оценен, и ваша функция будет выполнена. Вуаля, междоменные запросы!

Стоит также отметить одну важную проблему с JSONP: вы теряете контроль над запросом. Например, нет «хорошего» способа вернуть правильные коды ошибок. В результате вы используете таймеры для мониторинга запроса и т. Д., Что всегда немного подозрительно. Предложение для JSONRequest является отличным решением, позволяющим создавать междоменные сценарии, поддерживать безопасность и обеспечивать надлежащий контроль запроса.

В эти дни (2015) CORS является рекомендуемым подходом по сравнению с JSONRequest. JSONP по-прежнему полезен для поддержки старых браузеров, но с учетом последствий для безопасности, если у вас нет выбора, CORS - лучший выбор.

2021
Rahul Gupta 30 Май 2019 в 12:16

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

Вот сайт с отличными примерами , с объяснением от самого простого использования этого метода до самого продвинутого в плоскости JavaScript:

4PDA / JSONP

Один из моих самых любимых методов, описанных выше, это динамический результат JSON , который позволяет отправлять JSON в файл PHP с параметром URL , а также позволяет файлу PHP возвращать объект JSON, основанный на информации, которую он получает .

Такие инструменты, как jQuery также имеют возможности для использования JSONP:

jQuery.ajax({
  url: "https://data.acgov.org/resource/k9se-aps6.json?city=Berkeley",
  jsonp: "callbackName",
  dataType: "jsonp"
}).done(
  response => console.log(response)
);
1
simhumileco 20 Июл 2019 в 09:39

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 и т. Д.), Наш браузер сказал бы, что это не разрешено с этой ужасной ошибкой:

Chrome CORS console error

Как получить данные, которые мы хотим? Ну, <script> теги не подчиняются всему этому ограничению сервера (origin *)! Вот почему мы можем загружать такие библиотеки, как jQuery или Google Maps, с любого сервера, например, CDN, без каких-либо ошибок.

Важный момент : если подумать, эти библиотеки являются реальным, работающим кодом JS (обычно это большая функция со всей логикой внутри). Но необработанные данные? Даже в правильно отформатированном JSON есть не код . Там нет ничего, чтобы бежать; это просто простые данные.

Таким образом, мы не можем обрабатывать или манипулировать нашими ценными данными. Браузер загрузит данные, на которые указывает наш тег <script>, и при обработке будет по праву жаловаться:

WTF это {"user":"Smith"} дерьмо мы загрузили? Это не код Я не могу вычислить, синтаксическая ошибка!


Взлом JSONP

Старый / хакерский способ использовать эти данные? С точки зрения сервера с этими данными, он должен посылать их с некоторой логикой, чтобы при загрузке браузеры могли что-то контролировать и использовать эти данные. Таким образом, данные JSON помещаются в функцию JS в качестве аргумента. Это будет выглядеть так:

peopleDataJSONP({"user":"Smith"})

Что делает его кодом JS , наш браузер будет анализировать без жалоб! Чтобы получить его таким образом, от клиента мы «запрашиваем» JSON-дружественный сервер, обычно это делается так:

<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 применяется к другим данным (веб-шрифты, изображения / видео, нарисованные с помощью drawImage () ...)
  • Это не очень элегантно и не читабельно.

Вывод заключается в том, что в настоящее время нет необходимости использовать его .

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

Вы должны прочитать о CORS здесь, но суть этого является:

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



* происхождение определяется тремя вещами: протокол , порт и хост . Так, например, https://web.com отличается от источника, чем http://web.com (другой протокол) и https://web.com:8081 (другой порт), и, очевидно, https://thatotherweb.net (другой хост)

2
Carles Alcolea 21 Мар 2020 в 02:56

Хорошие ответы уже были даны, мне просто нужно представить свою часть в виде блоков кода в javascript (я также включу более современное и лучшее решение для запросов между источниками: CORS с заголовками HTTP):

< Сильный > JSONP :

1.client_jsonp.js

$.ajax({
    url: "http://api_test_server.proudlygeek.c9.io/?callback=?",
    dataType: "jsonp",
    success: function(data) {
        console.log(data);    
    }
});​​​​​​​​​​​​​​​​​​

2.server_jsonp.js

var http = require("http"),
    url  = require("url");

var server = http.createServer(function(req, res) {

    var callback = url.parse(req.url, true).query.callback || "myCallback";
    console.log(url.parse(req.url, true).query.callback);

    var data = {
        'name': "Gianpiero",
        'last': "Fiorelli",
        'age': 37
    };

    data = callback + '(' + JSON.stringify(data) + ');';

    res.writeHead(200, {'Content-Type': 'application/json'});
    res.end(data);
});

server.listen(process.env.PORT, process.env.IP);

console.log('Server running at '  + process.env.PORT + ':' + process.env.IP);

< Сильный > CORS :

3.client_cors.js

$.ajax({
    url: "http://api_test_server.proudlygeek.c9.io/",
    success: function(data) {
        console.log(data);    
    }
});​

4.server_cors.js

var http = require("http"),
    url  = require("url");

var server = http.createServer(function(req, res) {
    console.log(req.headers);

    var data = {
        'name': "Gianpiero",
        'last': "Fiorelli",
        'age': 37
    };

    res.writeHead(200, {
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*'
    });

    res.end(JSON.stringify(data));
});

server.listen(process.env.PORT, process.env.IP);

console.log('Server running at '  + process.env.PORT + ':' + process.env.IP);
4
Humoyun Ahmad 4 Дек 2018 в 02:39

Прежде чем понимать JSONP, вам нужно знать формат JSON и XML. В настоящее время наиболее часто используемым форматом данных в Интернете является XML, но XML очень сложен. Это делает пользователей неудобными для обработки встроенных в веб-страницах.

Чтобы JavaScript мог легко обмениваться данными, даже в качестве программы обработки данных, мы используем формулировку в соответствии с объектами JavaScript и разработали простой формат обмена данными, который является JSON. JSON можно использовать как данные или как программу JavaScript.

JSON может быть непосредственно встроен в JavaScript, используя их, вы можете напрямую выполнять определенную программу JSON, но из-за ограничений безопасности механизм песочницы браузера отключает междоменное выполнение кода JSON.

Чтобы JSON можно было передать после выполнения, мы разработали JSONP. JSONP обходит пределы безопасности браузера с помощью функции обратного вызова JavaScript и тега

JSONP отлично подходит для обхода ошибок междоменных сценариев. Вы можете использовать сервис JSONP исключительно с JS без необходимости в реализации прокси AJAX на стороне сервера.

Вы можете использовать b1t.co сервис, чтобы посмотреть, как он работает. Это бесплатный сервис JSONP, который позволяет минимизировать ваши URL-адреса. Вот URL для использования в сервисе:

http://b1t.co/Site/api/External/MakeUrlWithGet?callback=[resultsCallBack visible&url=[escapedUrlToMinify]

Например, вызов http://b1t.co/Site/ api / External / MakeUrlWithGet? callback = anyJavascriptName & url = google.com

Вернется

whateverJavascriptName({"success":true,"url":"http://google.com","shortUrl":"http://b1t.co/54"});

И поэтому, когда он загружается в ваш js как src, он автоматически запускает любое имя Javascript, которое вы должны реализовать в качестве функции обратного вызова:

function minifyResultsCallBack(data)
{
    document.getElementById("results").innerHTML = JSON.stringify(data);
}

Чтобы фактически сделать вызов JSONP, вы можете сделать это несколькими способами (включая использование jQuery), но вот чистый пример JS:

function minify(urlToMinify)
{
   url = escape(urlToMinify);
   var s = document.createElement('script');
   s.id = 'dynScript';
   s.type='text/javascript';
   s.src = "http://b1t.co/Site/api/External/MakeUrlWithGet?callback=resultsCallBack&url=" + url;
   document.getElementsByTagName('head')[0].appendChild(s);
}

Пошаговый пример и веб-сервис jsonp, с которым можно попрактиковаться, доступны по адресу: в этом посте

19
dardawk 5 Апр 2013 в 15:20

Потому что вы можете попросить сервер добавить префикс к возвращенному объекту JSON. Например

function_prefix(json_object);

Чтобы браузер eval «встроил» строку JSON в качестве выражения. Этот трюк позволяет серверу «вставлять» код JavaScript непосредственно в браузер клиента, что позволяет обойти ограничения «одного источника».

Другими словами, вы можете иметь междоменный обмен данными .


Обычно XMLHttpRequest не разрешает междоменный обмен данными напрямую (необходимо пройти через сервер в том же домене), тогда как:

<script src="some_other_domain/some_data.js&prefix=function_prefix> `можно получить доступ к данным из домена, отличного от исходного.


Также стоит отметить: несмотря на то, что сервер должен рассматриваться как «доверенный» перед попыткой такого рода «уловки», побочные эффекты возможного изменения формата объекта и т. Д. Могут быть ограничены. Если function_prefix (то есть правильная функция js) используется для получения объекта JSON, указанная функция может выполнить проверки перед принятием / дальнейшей обработкой возвращенных данных.

41
Jackson 13 Фев 2015 в 09:22

JSONP работает путем создания элемента «script» (либо в разметке HTML, либо вставляется в DOM через JavaScript), который запрашивает расположение удаленной службы данных. Ответ представляет собой JavaScript, загруженный в ваш браузер с именем предварительно определенной функции и передаваемым параметром, который запрашивает данные JSON. Когда скрипт выполняется, функция вызывается вместе с данными JSON, что позволяет запрашивающей странице получать и обрабатывать данные.

Для дальнейшего чтения: https: // blogs.sap.com/2013/07/15/secret-behind-jsonp/

фрагмент кода на стороне клиента

    <!DOCTYPE html>
    <html lang="en">
    <head>
     <title>AvLabz - CORS : The Secrets Behind JSONP </title>
     <meta charset="UTF-8" />
    </head>
    <body>
      <input type="text" id="username" placeholder="Enter Your Name"/>
      <button type="submit" onclick="sendRequest()"> Send Request to Server </button>
    <script>
    "use strict";
    //Construct the script tag at Runtime
    function requestServerCall(url) {
      var head = document.head;
      var script = document.createElement("script");

      script.setAttribute("src", url);
      head.appendChild(script);
      head.removeChild(script);
    }

    //Predefined callback function    
    function jsonpCallback(data) {
      alert(data.message); // Response data from the server
    }

    //Reference to the input field
    var username = document.getElementById("username");

    //Send Request to Server
    function sendRequest() {
      // Edit with your Web Service URL
      requestServerCall("http://localhost/PHP_Series/CORS/myService.php?callback=jsonpCallback&message="+username.value+"");
    }    

  </script>
   </body>
   </html>

Серверная часть кода PHP

<?php
    header("Content-Type: application/javascript");
    $callback = $_GET["callback"];
    $message = $_GET["message"]." you got a response from server yipeee!!!";
    $jsonResponse = "{\"message\":\"" . $message . "\"}";
    echo $callback . "(" . $jsonResponse . ")";
?>
47
Liam Hammett 22 Май 2017 в 14:20

JSONP - это действительно простая уловка для преодоления политики XMLHttpRequest в том же домене. (Как вы знаете, нельзя отправить запрос AJAX (XMLHttpRequest) в другой домен.)

Поэтому вместо использования XMLHttpRequest мы должны использовать HTML-теги script , которые вы обычно используете для загрузки js-файлов, чтобы js мог получать данные из другого домена. Звучит странно?

Дело в том, что теги script можно использовать аналогично XMLHttpRequest ! Проверь это:

script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.someWebApiServer.com/some-data';

В результате вы получите сегмент script , который выглядит следующим образом после загрузки данных:

<script>
{['some string 1', 'some data', 'whatever data']}
</script>

Однако это немного неудобно, потому что мы должны извлечь этот массив из тега script . Поэтому создатели JSONP решили, что это будет работать лучше (и это так):

script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.someWebApiServer.com/some-data?callback=my_callback';

Обратите внимание на функцию my_callback там? Итак, когда JSONP сервер получит ваш запрос и найдет параметр обратного вызова - вместо возврата обычного массива js он вернет следующее:

my_callback({['some string 1', 'some data', 'whatever data']});

Посмотрите, где прибыль: теперь мы получаем автоматический обратный вызов (my_callback), который сработает после получения данных.
Вот и все, что нужно знать о JSONP : это обратный вызов и теги сценария.

ПРИМЕЧАНИЕ. Это простые примеры использования JSONP, это не готовые производственные сценарии.

Базовый пример JavaScript (простой канал Twitter с использованием JSONP)

<html>
    <head>
    </head>
    <body>
        <div id = 'twitterFeed'></div>
        <script>
        function myCallback(dataWeGotViaJsonp){
            var text = '';
            var len = dataWeGotViaJsonp.length;
            for(var i=0;i<len;i++){
                twitterEntry = dataWeGotViaJsonp[i];
                text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'
            }
            document.getElementById('twitterFeed').innerHTML = text;
        }
        </script>
        <script type="text/javascript" src="http://twitter.com/status/user_timeline/padraicb.json?count=10&callback=myCallback"></script>
    </body>
</html>

Базовый пример jQuery (простой канал Twitter с использованием JSONP)

<html>
    <head>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
        <script>
            $(document).ready(function(){
                $.ajax({
                    url: 'http://twitter.com/status/user_timeline/padraicb.json?count=10',
                    dataType: 'jsonp',
                    success: function(dataWeGotViaJsonp){
                        var text = '';
                        var len = dataWeGotViaJsonp.length;
                        for(var i=0;i<len;i++){
                            twitterEntry = dataWeGotViaJsonp[i];
                            text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'
                        }
                        $('#twitterFeed').html(text);
                    }
                });
            })
        </script>
    </head>
    <body>
        <div id = 'twitterFeed'></div>
    </body>
</html>


JSONP означает JSON с заполнением . (очень плохо названная техника, поскольку она на самом деле не имеет ничего общего с тем, что большинство людей считает «заполнением».)

707
Eric 15 Мар 2018 в 07:57