Что такое JSONP?

В последнее время довольно часто замечал в разных статьях упоминание о JSONP. Судя по названию это тот же JSON, но с каким-то наворотом. Поразобравшись немного с этим, оказалось что этот формат нужен для того, чтобы иметь возможность выполнять асинхронные запросы к серверу расположенному на другом домене. Напомню, что для объекта XMLHTTPRequest есть такое ограничение. То есть, если ваш сайт расположен по адресу mysite.com, то AJAX запрос на сервер anothersite.com выполнить не удастся.

Так вот, чтобы обойти это ограничение поступали следующим образом – динамически создавали и добавляли в документ новый тег <script>, который подгружал скрипт с нужными данными:

<script src="/some/url/here" type="text/javascript"></script>

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

var data = {
    one : "12",
    two : "34"
}

someCallback(data);

Если в указанном выше примере не объявлять переменную data, а сразу поместить её в вызов someCallback, то получим то, что сейчас стали называть JSONP:

someCallback({ one : "12",  two : "34" });

В данный момент некоторые популярные сервисы поддерживают как JSON, так и JSONP. Типичным примером является API для поиска от YAHOO. Чтобы получить данные от сервера в виде JSON, мы указываем параметр output=json:

http://search.yahooapis.com/WebSearchService/V1/webSearch?appid=YahooDemo&query=finances&format=pdf&output=json

Теперь, чтобы получить данные в виде JSONP, просто добавляем название функции-callback, в которую будут “завернуты” возвращаемые данные. Указанная выше ссылка будет выглядеть так:

http://search.yahooapis.com/WebSearchService/V1/webSearch?appid=YahooDemo&query=finances&format=pdf&output=json&callback=loadit

По этой ссылке сервер вернет следующие данные:

loadit({"ResultSet":{"type":"web","totalResultsAvailable":22600000,"totalResultsReturned":10, ... } });

Теперь, короткий пример получения и обработки формата JSONP:

<html>
<head>
<script type="text/javascript">

// callback
function loadit(data) {
  // работаем с данными
  if (!data) {
    return;
  }

  var oTotal = document.getElementById("total");
  oTotal.innerHTML = data.ResultSet.totalResultsAvailable;
}

// здесь будет ссылка на новый элемент script
var oElem = null;

function sendJSONP(url, callback) {
  if (!url || !callback)
    return;

  url += '&callback='+callback;

  // выполняем запрос JSONP
  if (oElem) {
    oElem.parentNode.removeChild(oElem);
  }

  oElem = document.createElement('script');
  oElem.setAttribute('type','text/javascript');
  document.getElementsByTagName('head')[0].appendChild(oElem);
  oElem.setAttribute('src', url);
}

window.onload = function(){
  document.getElementById("searchBtn").onclick = function(){
    var query = document.getElementById("query").value;
    sendJSONP('http://search.yahooapis.com/WebSearchService/V1/webSearch?appid=YahooDemo&query='+encodeURIComponent(query)+'&output=json', 'loadit');
  }
}
</script>
</head>
<body>
<input type="text" name="search" value="" id="query" /><input type="button" value="Искать" name="s" id="searchBtn"/>
<div id="total"></div>
</body>
</html>

Этот скрипт работает следующим образом: пользователь вводит в поле поиска искомую фразу и нажимает на кнопку “Искать”. Из возвращаемых результатов поиска мы выделяем значение общего количества результатов totalResultsAvailable и показываем это значение в элементе <div id=total>. Запрос к серверу выполняется в функции sendJSONP, которая принимает 2 параметра – url и callback.

В библиотеке jQuery имеется встроенная поддержка формата JSONP. При использовании этого фреймворка, нет нужды самому код, который добавляет тег SCRIPT в DOM. Всё, что нужно будет сделать, это изменить URL, чтобы указать jQuery, что выполняется JSONP запрос. Заканчивая URL вопросительным знаком, мы даем jQuery понять, что получаемые данные будут в формате JSONP. Не нужно также и указывать название функции обработчика. Пример:

<html>
<head>
<script src="/jquery/jquery.js"></script>
<script>
var baseurl = 'http://search.yahooapis.com/ImageSearchService/V1/imageSearch?appid=YahooDemo&output=json&query='

function search() {
     var search = $("#search").val()
     console.log(search)
     var surl = baseurl + escape(search) + '&callback=?'
     $.getJSON(surl, function(data) {
          var res = '<h1>Search for '+search+'</h1>'
          res += '<p>There were '+data.ResultSet.totalResultsAvailable+' results.</p>'
          for(var i=0; i<data.ResultSet.Result.length; i++) {
               var result = data.ResultSet.Result[i]
               var resultStr = '<img src="'+result['Thumbnail']['Url']+'" align="left">';
               resultStr += '<a href="'+result['ClickUrl']+'">'+result['Title']+'</a><br clear="left"/>'
               res+=resultStr
           }
          $("#result").html(res)
      })
}
$(document).ready(function() {
     $("#searchBtn").click(search)
});

</script>
</head>

<body>
    <input type="text" name="search" id="search"> <input type="button" value="Search" id="searchBtn">
    <div id="result"></div>
</body>
</html>

Этот пример для работы с jQuery позаимствован на InsideRIA.

Поддержка JSONP скоро будет доступна и в Mootools. В данный момент она уже есть в версии 1.3rc1. Выглядит это так:

new JsonP('http://api.cnet.com/restApi/v1.0/techProductSearch', {
    data: {
        partTag: 'mtvo',
        iod: 'hlPrice',
        iewType: 'json',
        results: '100',
        query: 'ipod'
    },
    onComplete: myFunction.bind(someObject)
}).request();

На мой взгляд гораздо понятнее и проще, чем чудеса с вопросительными знаками в jQuery :)

Maklay.com - Большой каталог товаров для спорта и активного отдыха
  • http://www.aos.com.ua nice

    Спасибо!!! Хоть буду значь что это )

  • Link

    Всё новое хорошо забытое старое :) Из нового это название и передача данных только JSON.
    Так рождался аякс, когда нормальной поддержки не было во всех браузерах.
    Честно говоря всегда было интересно, какое главное преимущество AJAX перед динамической подгрузкой JS.

  • http://mabp.kiev.ua/2009/03/22/linkdump-11/ Linkdump #11 | CTAPbIu_MABP’s BLOG

    [...] Что такое JSONP? Для новичков… [...]

  • Serge

    Отлично все объяснил, спасибо.

  • http://www.jstoolbox.com/2009/07/23/yahoo-query-language/ YAHOO Query Language | JSToolbox – все о JavaScript

    [...] кажется, что самый простой вариант это использование JSONP, ибо, как я уже писал выше, YQL запрос поддерживает [...]

  • http://cgi2m.net.ua alexander

    Разговорчива эта хрень чересчур. Если бы все недолугие горе-разработчики платили нам за переизпользованный траффик, мы бы озолотились. Так, например на одном из сайтов с такими наворотами для загрузки таблички в 47 кбайт выворачивается более 7 мбайт. Про тугодумство и зависимость от передаваемых данных я просто молчу…

JSToolbox создан на основе WordPress