Книга: JavaScript. Подробное руководство, 6-е издание
18.2. Выполнение НТТР-запросов с помощью : JSONP
Разделы на этой странице:
18.2. Выполнение НТТР-запросов с помощью <script>: JSONP
В начале этой главы упоминалось, что элемент <script>
можно использовать в качестве Ajax-транспорта: достаточно установить атрибут src
элемента <script>
(и вставить его в документ, если он еще не внутри документа), и броузер сгенерирует HTTP-запрос, чтобы загрузить содержимое ресурса по указанному URL-адресу. Основная причина, почему элементы <script>
являются удобным Ajax-транспортом, состоит в том, что они не являются субъектами политики общего происхождения и их можно использовать для запроса данных с других серверов. Вторая причина состоит в том, что элементы <script>
автоматически декодируют (т. е. выполняют) тело ответа, содержащего данные в формате JSON.
Прием использования элемента <script>
в качестве Ajax-транспорта известен под названием JSONP: это способ организации взаимодействий, когда в теле ответа на HTTP-запрос возвращаются данные в формате JSON. Символ «Р» в аббревиатуре означает «padding», или «prefix» (дополнение или приставка), но об этом чуть ниже.[51]
Представьте, что вы пишете службу, которая обрабатывает GET-запросы и возвращает данные в формате JSON. Документы с общим происхождением могут пользоваться этой службой с помощью объекта XMLHttpRequest
и метода JSON.parse()
, как показано в примере 18.3. Если на сервере будет настроена отправка заголовка «CORS», сторонние документы при отображении в новых броузерах также смогут пользоваться службой с помощью объекта XMLHttpRequest
. Однако при отображении в старых броузерах, не поддерживающих заголовок «CORS», сторонние документы смогут получить доступ к службе только с помощью элемента <script>.
Ответ в формате JSON является (по определению) допустимым программным кодом на языке JavaScript, и броузер выполнит его при получении. При выполнении данных в формате JSON происходит их декодирование, но полученный результат является обычными данными, которые ничего не делают.
Именно здесь на сцену выходит символ «Р» из аббревиатуры JSONP. Когда обращение к службе реализовано с помощью элемента <script>,
служба должна «дополнить» ответ, окружив его круглыми скобками и добавив в начало имя JavaScript-функции. То есть вместо того чтобы отправлять данные, такие как:
[1, 2, {"buckle": "my shoe”}]
она должна отправлять дополненные данные, как показано ниже:
handleResponse(
[1. 2. {"buckle": "my shoe"}]
Являясь телом элемента <script>,
этот дополненный ответ уже будет выполнять некоторые действия: он произведет преобразование данных из формата JSON (которые в конечном итоге являются одним длинным выражением на языке JavaScript) и передаст их функции handleResponse(),
которая, как предполагается, определена в теле документа и выполняет некоторые операции с данными.
Сценарии и безопасность
Используя элемент <script> в качестве Ajax-транспорта, вы разрешаете своей веб-странице выполнять любой программный код на языке JavaScript, который отправит удаленный сервер. Это означает, что прием, описываемый здесь, не должен использоваться при работе с серверами, не вызывающими доверия. Впрочем, даже при работе с доверенным сервером следует помнить, что этот сервер может быть взломан злоумышленником, и злоумышленник сможет заставить вашу веб-страницу выполнить любой программный код и отобразить любую информацию, какую он пожелает, и эта информация будет выглядеть, как если бы она поступила с вашего сайта.
При этом следует отметить, что для веб-сайтов стало обычным делом использовать доверенные сценарии сторонних разработчиков, особенно сценарии, используемые для внедрения в страницу рекламы или «виджетов». Использование элемента <script> в качестве Ajax-транспорта для взаимодействия с доверенными веб-службами ничуть не опаснее.
*************************************
Чтобы этот прием действовал, необходимо иметь некоторый способ сообщить службе, что обращение к ней выполняется с помощью элемента <script>
и она должна возвращать ответ не в формате JSON, а в формате JSONP. Это можно сделать, указав параметр запроса в адресе URL, например, добавив в конец ?jsonp
(или &jsonp
).
На практике веб-службы, поддерживающие JSONP, не диктуют имя функции, такое как «handleResponse», которую должны реализовать все клиенты. Вместо этого они используют значение параметра запроса, позволяя клиентам самим указывать имя функции, и применяют его для дополнения ответа. В примере 18.14 для определения имени функции обратного вызова используется параметр «jsonp». Многие службы, поддерживающие JSONP, распознают параметр с эти именем. Также достаточно часто используется параметр с именем «callback», и вы можете изменить программный код примера, чтобы он смог работать со службами, предъявляющими определенные требования.
Пример 18.14 определяет функцию get JS0NP(), которая выполняет запрос на получение данных в формате JSONP. В этом примере есть несколько тонкостей, о которых следует сказать особо. Во-первых, обратите внимание, что пример создает новый элемент <script>,
устанавливает его URL-адрес и вставляет элемент в документ. Операция вставки вызывает выполнение HTTP-запроса. Во-вторых, для каждого запроса в этом примере создается новая внутренняя функция обратного вызова, которая сохраняется в свойстве самой функции getJSONP().
Наконец, эта функция обратного вызова выполняет необходимые заключительные операции: она удаляет элемент <script> и саму себя.
Пример 18.14. Выполнение запросов на получение данных в формате JSONP с помощью элемента <script>
// Выполняет запрос по указанному URL-адресу на получение данных в формате JSONP и передает
// полученные данные указанной функции обратного вызова. Добавляет в URL параметр запроса
// с именем ''jsonp'', чтобы указать имя функции обратного вызова,
function getJS0NP(иrl, callback) {
// Создать для данного запроса функцию с уникальным именем
var cbnum = "cb" + getJSONP.counter++; // Каждый раз увеличивать счетчик
var cbname = "getJSONP.” + cbnum; // Как свойство этой функции
// Добавить имя функции в строку запроса url, используя формат представления данных
// HTML-форм. Здесь используется параметр с именем "jsonp". Некоторые веб-службы
// с поддержкой JSONP могут использовать параметр с другим именем, таким как "callback",
if (url.indexOfC?") === -1) // URL еще не имеет строки запроса
url += "?jsonp=" + cbname; // добавить параметр как строку запроса
else // В противном случае
url += "&jsonp=" + cbname; // добавить как новый параметр.
// Создать элемент script, который отправит запрос
var script = document.createElement("script");
// Определить функцию, которая будет вызвана сценарием
getJSONP[cbnum] = function(response) {
try {
callback(response); // Обработать данные
}
finally { // Даже если функция или ответ возбудит исключение
delete getJSONP[cbnum]; // Удалить эту функцию
script.parentNode.removeChild(script); // Удалить элемент script
}
};
// Инициировать HTTP-запрос
script.src = url; // Указать url-адрес элемента
document.body.appendChild(script); // Добавить в документ
}
getJSONP.counter = 0; // Счетчик, используемый для создания уникальных имен
- Повышение производительности приложений с помощью хранимых процедур
- Тестирование Web-сервиса XML с помощью WebDev.WebServer.exe
- Организация пользователей в группы с помощью ролей
- Улучшенный оптимизатор запросов
- Асинхронный сервер и отмена выполняющихся запросов
- 1. Оператор Select – базовый оператор языка структурированных запросов
- 2. Унарные операции на языке структурированных запросов
- 3. Бинарные операции на языке структурированных запросов
- 4. Использование подзапросов
- Обработка запросов с помощью PHP
- Как с помощью компьютера подшутить над друзьями и коллегами?
- Как составить психологический портрет с помощью Сети?