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

1884

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

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

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

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

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

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


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


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

  • 55
    Скаффман, могу ли я считать, что из твоего взгляда из глубины души ты тот, кто удалил совершенно разумные вопросы из Википедии? Без добавления чего-либо или улучшения? Как это «вандализм» задавать вопрос. Sheesh. И да, в этот самый момент я собираюсь улучшить страницу википедии, предоставив информацию, предоставленную jvenema.
  • 19
    Для записи НЕ используйте JSONP, если вы не доверяете серверу, на котором говорите на 100%. Если это скомпрометировано, ваша веб-страница будет скомпрометирована.
Показать ещё 3 комментария
Теги:
jsonp
terminology

8 ответов

1747
Лучший ответ

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

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

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

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

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

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

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

{ foo: 'bar' }

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

mycallback({ foo: 'bar' });

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

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

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

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

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

  • 159
    Обратите внимание, что использование JSONP имеет некоторые последствия для безопасности. Поскольку JSONP действительно является javascript, он может делать все остальное, что может делать javascript, поэтому вам нужно доверять поставщику данных JSONP. Я написал сообщение в блоге об этом здесь: erlend.oftedal.no/blog/?blogid=97
  • 66
    Действительно ли в JSONP есть какие-то новые аспекты безопасности, которых нет в теге <script>? С помощью тега script браузер неявно доверяет серверу доставку неопасного Javascript, который браузер слепо оценивает. JSONP меняет этот факт? Кажется, нет.
Показать ещё 30 комментариев
687

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. (очень плохо названная техника, так как она действительно не имеет ничего общего с тем, что большинство людей будет воспринимать как "заполнение".)

  • 33
    Спасибо за объяснение тега сценария. Я не смог понять, как JSONP обошел политику междоменной безопасности. После объяснения я чувствую себя немного глупо, чтобы упустить момент ...
  • 13
    Это очень хороший дополнительный ответ на ответ jvenema - я не понимал, почему обратный вызов был необходим, пока вы не указали, что в противном случае к данным json придется обращаться через элемент script.
Показать ещё 7 комментариев
39

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 . ")";
?>
36

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

function_prefix(json_object);

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

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


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

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


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

17

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

10

Простой пример использования 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;

    ?>    
9

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

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

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

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

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

  • 4
    Я опроверг это, потому что я не верю утверждению, что XML был наиболее часто используемым форматом данных в сети в декабре 15 года.
0

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню