Что такое JSONP и почему он был создан?

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

JSONP или "JSON с дополнением" - это расширение JSON, в котором префикс указан как входной аргумент самого вызова.

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

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

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

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


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


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

Ответ 1

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

Допустим, вы находитесь на домене 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 - лучший выбор.

Ответ 2

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: это обратный вызов и теги script.

ПРИМЕЧАНИЕ. Это простые примеры использования 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 с Padding. (очень плохо названная техника, так как она действительно не имеет ничего общего с тем, что большинство людей будет воспринимать как "заполнение".)

Ответ 3

JSONP работает, создавая элемент "script" (либо в разметке HTML, либо вставляется в DOM через JavaScript), который запрашивает местоположение удаленной службы данных. Ответ - это javascript, загруженный в ваш браузер с именем предопределенной функции вместе с передаваемым параметром, который запрашивает данные JSON. Когда выполняется script, функция вызывается вместе с данными 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 . ")";
?>

Ответ 4

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

function_prefix(json_object);

чтобы браузер eval "встроил" строку JSON в качестве выражения. Этот трюк позволяет серверу "вводить" javascript-код непосредственно в браузере клиента, и это обходит ограничения "того же происхождения".

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


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

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


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

Ответ 5

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

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

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

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

вернет

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

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

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

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

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 для практики доступны по адресу: этот пост

Ответ 6

Простой пример использования JSONP.

client.html

    <html>
    <head>
   </head>
     body>


    <input type="button" id="001" onclick=gO("getCompany") value="Company"  />
    <input type="button" id="002" onclick=gO("getPosition") value="Position"/>
    <h3>
    <div id="101">

    </div>
    </h3>

    <script type="text/javascript">

    var elem=document.getElementById("101");

    function gO(callback){

    script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = 'http://localhost/test/server.php?callback='+callback;
    elem.appendChild(script);
    elem.removeChild(script);


    }

    function getCompany(data){

    var message="The company you work for is "+data.company +"<img src='"+data.image+"'/   >";
    elem.innerHTML=message;
}

    function getPosition(data){
    var message="The position you are offered is "+data.position;
    elem.innerHTML=message;
    }
    </script>
    </body>
    </html>

server.php

  <?php

    $callback=$_GET["callback"];
    echo $callback;

    if($callback=='getCompany')
    $response="({\"company\":\"Google\",\"image\":\"xyz.jpg\"})";

    else
    $response="({\"position\":\"Development Intern\"})";
    echo $response;

    ?>    

Ответ 7

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

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

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

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

Итак, кратко объясняет, что такое JSONP, какую проблему он решает (когда его использовать).

Ответ 8

Большие ответы уже были даны, мне просто нужно предоставить свою часть в виде блоков кода в 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);

Ответ 9

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)
);