Кросдоменный JavaScript (JSONP)

Автор: Вячеслав Гринин | веб-программирование | 10 Окт 2009 4:41 пп

Итак, мы уже научились использовать объект XMLHttpRequest для фоновой загрузки данных с сервера, этот подход подробно описан в статье AJAX. 1 – Что это такое?. Однако, приведенный метод обладает одним недостатком – он не позволяет делать кроссдоменные запросы, то есть скрипт расположенный на домене easy4web.ru не может обратиться к домену vision4web.ru, а иногда этого так хочется. И здесь нам на помощь придет метод динамически подгружаемых скриптов <SCRIPT>.

Как известно, HTML-элемент <SCRIPT> может загружаться и с чужого домена, то есть аттрибут src у него может указывать вообще на любой домен. При этом, сразу после загрузки в нашу страницу, скрипт начнет выполняться. Таким образом, вставив в этот скрипт вызов некой заранее известной функции, мы можем организовать оповещение страницы о том, что скрипт загружен и готов к выполнению работы. А данные для для скрипта можно упаковать в пакет JSON. Такой комбинированный подход носит имя JSONP (JSON with padding).

На клиентской стороне мы выполняем такой код:

  var script = document.createElement("script");
  script.src = 'http://mydomain.ru/script.php?callback=func1';
  script.type = 'text/javascript';
  document.body.appendChild(script);

А по адресу  http://mydomain.ru/script.php поселим вот такой код:

<?php
echo($_REQUEST['callback'].'({"result":"Успешно!"})');
?>

На клиентской стороне также существует такой callback (то есть функция, которая сработает после загрузки скрипта):

function func1(response)
{
  alert(response.result);
}

Протестировать рабочий пример можно здесь: http://easy4web.ru/samples/jsonp/index.html, а скачать код вышеприведенного примера можно здесь: http://easy4web.ru/images/jsonp.zip

В тестовом примере, как можно увидеть, не происходит кроссдоменной загрузки – мы загружаем с того же домена, где расположен скрипт. Но вы можете заменить URL в этом месте кода:

<input type="button" value="Получить JSONP"
 onclick="getJSONP('http://easy4web.ru/samples/jsonp/handler.php',onSuccess)"/>

на ваш собственный или на наш тестовый handler, расположенный на другом домене, (вот здесь http://vision4web.ru/api/handler.php) и убедиться в том, что кроссдоменная загрузка прекрасно работает.

Ниже приведен скриншот сетевого взаимодействия:
screen

Как видно, при нажатии на кнопку “Получить JSONP” происходит создание элемента <SCRIPT> с атрибутом src=http://easy4web.ru/samples/jsonp/handler.php, при этом браузер тут же начинает загружать этот скрипт с удаленного сервера. А загруженный скрипт представляет собой вызов функции onSuccess() с параметром {”result”:”Успешно!”}. После загрузки скрипта он тут же начинает выполняться, тем самым выполняя функцию OnSuccess, которая, получив в качестве аргумента JSON-объект, обрабатывает его и совершает все необходимые действия, обусловленные логикой приложения.

Этот подход я собираюсь использовать при реализации многих полезных сервисов в рамках проекта easyAPI.

Прочтите еще:

Отзывов: 7 »

  1. Отзыв Vladimir — Март 4, 2010 в 11:06 пп

    Проверить отображение страницы в последних версиях Mozilla- текст смещен влево!!!

  2. Отзыв admin — Март 5, 2010 в 10:27 дп

    :)

  3. Отзыв admin — Март 5, 2010 в 12:41 пп

    А кодировка в RSS не глючит? Или в Опере футер не смещен?

  4. Отзыв Алексей — Июль 2, 2010 в 8:30 дп

    Подскажите, плиз, почему у меня в Опере не работает этот пример, в Мозиле и ИЕ – работает.

  5. Отзыв admin — Июль 7, 2010 в 8:29 пп

    Как именно не работает? Что пишет? Как Вы его используете? Возможно у Оперы что-то в последних версиях поменялось в плане безопасности. Нужно Ваше подробное описание.

  6. Отзыв Алексей — Июль 9, 2010 в 3:23 пп

    я внес некоторые изменения, поэтому не работает. Ваш пример работает. Подскажите, есть ли возможность запустить функцию getJSONP(…) без кнопки. Я пробовал просто писать:

    // Callback
    function onSuccess(response) {
    document.getElementById(”result”).innerHTML=response.result;
    }
    getJSONP(’http:….’,onSuccess);

    В Мозиле работает, в ИЕ – в последних версиях, в Опере – нет. В ИЕ, где не рабатет, выдает ошибка document.getElementById(…) – есть null или не является объектом

  7. Отзыв admin — Июль 24, 2010 в 12:16 пп

    Ваш код так выборочно работает из-за разной модели рендеринга в разных версиях разных браузеров. В тех случаях, когда Ваш код не работает, получается следующая ситуация: Страница начинает загружаться, доходит до того момента где у Вас стоит вызов getJSONP(), вызывает его, получает с сервера результат, вызывает функцию onSuccess(), но к этому времени рендеринг страницы дошел только до момента, где вызывается функция getJSONP(), а вот сам BODY документа вместе с дивом result еще не создан в модели документа, вот браузер и выдает ошибку is null.

    Некоторые браузеры делают загрузку и рендеринг параллельно, а поэтому когда вызывается onSuccess(), остальная часть страницы уже прорендерена и ошибки не возникает.
    Чтобы сработал Ваш подход, вам нужно ставить вызов getJSONP(’http:….’,onSuccess); не там где он у Вас, а либо в блоке SCRIPT, создаваемом после блока BODY, либо ставить вызов на собитие onload Документа, то есть как-то так <BODY onload=”getJSONP(’http:….’,onSuccess);”>

RSS-лента комментариев. Адрес для трекбека

Ваш отзыв