Что такое JSONP и почему он был создан? - PullRequest
1982 голосов
/ 14 января 2010

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

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

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

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

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

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


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


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

Ответы [ 8 ]

1924 голосов
/ 15 января 2010

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

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

678 голосов
/ 30 июля 2011

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

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

Дело в том - получается скрипт теги можно использовать аналогично 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<b>?callback=my_callback</b>';

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

43 голосов
/ 17 марта 2013

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 . ")";
?>
39 голосов
/ 14 января 2010

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

function_prefix(json_object);

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

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


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

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


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

19 голосов
/ 28 марта 2013

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

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

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

12 голосов
/ 06 июня 2014

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

    ?>    
10 голосов
/ 08 декабря 2015

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

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

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

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

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

3 голосов
/ 04 декабря 2018

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