Кросс-доменный Ajax в jQuery Javascript
4 jQuery Cross-Domain AJAX Request methods
The web has changed and with it the way we develop websites. Today, the web is becoming a place where we develop web apps, rather than websites. We use third party API’s to create our next mashups. So knowing how to make a cross-site AJAX request or requests that do not comply with the same origin policy is a must. In this article, you will learn 4 cross-site AJAX request methods (plus 4 bonus legacy methods and links to jQuery plugins).
This methods will be handy to overcome Same origin policy as well. Browsers will throw an error if you are making AJAX request to the same domain but with different protocol (to https from http), use different port (https://same-domain.com:81) or subdomain.
This article reviews the following 4 methods and discusses their advantages & disadvantages. Also, summarise cases when they are better used.
Here is the list of methods:
Before we dive into the method details, let’s cover most common cases:
- Firstly, if you are trying to read data that is available as RSS feed, you are better off with universal RSS to JSON converter powered by Google.
- Secondly, if you are accessing data from some popular website API, it’s more likely they support JSONP as well. See their documentation.
JSONP is a cross browser method that does not rely on any browser hacks. It is supported by all browsers and many javascript libraries provide methods that make JSONP request seamless.
1. CORS (Cross-Origin Resource Sharing)
CORS is a W3C recommendation and supported by all major browsers. It makes use of HTTP headers to help browser decide if a cross-domain AJAX request is secure. Basically, when you make a CORS request, browser adds Origin header with the current domain value. For example:
The server, where the script makes its’ CORS request, checks if this domain is allowed and sends response with Access-Control-Allow-Origin response header. Upon receiving, browser checks if the header is present and has the current domain value. If domains match, browser carries on with AJAX request, if not throws an error.
To make a CORS request you simply use XMLHttpRequest in Firefox 3.5+, Safari 4+ & Chrome and XDomainRequest object in IE8+. When using XMLHttpRequest object, if the browser sees that you are trying to make a cross-domain request it will seamlessly trigger CORS behaviour.
Here is a javascript function that helps you create a cross browser CORS object.
Function takes 2 arguments: method — request method («GET», «POST», etc.) and url — URL where to send the request. Here is how to make a «GET» request to Google.
Because CORS specification relies on HTTP headers and all the heavy lifting is done by browser and server, our code does not need to change. In other words, you can make cross-domain AJAX requests like any other in jQuery.
Requirements & Notes
In order to be able to make a CORS request, you need CORS supporting browser and a server. Check if your browser and server support it.
Also note, that if AJAX request adds any custom HTTP headers or use any method other than GET, POST or HEAD as a request type; browser will make a «preflight» request to check if the server responds with correct headers before sending the actual request. This adds an overhead to your AJAX requests.
Advantages & Disadvantages
CORS is a W3C specification and supported by all major browsers. It is how the cross domain AJAX querying will work in the future. So using CORS would be a future safe bet.
However, it requires CORS supporting server and browser. If you have administrative privileges at the server you can add CORS support as explained here. If you do not have any control over the server, then you are out of luck. You will need to choose some other method.
2. JSONP (JSON Padding)
Because of the same origin policy, we can not make cross domain AJAX requests, but we can have
Кросс-доменный Ajax в jQuery Javascript
Сегодня мы поговорим про AJAX. Напомню, что в прошлый раз мы рассматривали пример хорошего AJAX-а. Там мы показали, как нужно делать, чтобы пользователь не чувствовал себе некомфортно.
В этой статье я хочу рассказать про кроссдоменный AJAX. Что в нем особенного? Дело в том, что объект JavaScript XmlHttpRequest, который во всех популярных фреймворках реализует AJAX, не поддерживает кроссдоменные запросы по соображениям безопасности. Но иногда же очень нужно через JS запросить какую-нибудь страничку с другого сайта, да? Варианты есть, так что читаем дальше и выбирает то, что нужно именно для вашей задачи.
Задача
Допустим, вам нужно с помощью JS запросить какой-то файл с другого сервера. Стандартными методами AJAX это сделать нельзя, так как объект XmlHttpRequest работает только в пределах одного домена.
Сразу оговорюсь, что для решения этой задачи необходимо как минимум, чтобы вы как разработчик имели доступ к файлам на обоих серверах (с которого идет запрос и тот, где нужный файл), так как отдаваемые с удаленного сервера файлы должны быть в особом (для каждого отдельного решения) формате.
Решения 1: использование серверных скриптов у себя как прокси
Самы простой вариант — использовать собственный сервер как прокси. То есть вы из своего js-приложения обращаетесь к скриптам на этом же сервере и указываете ему адрес и формат возвращаемой информации (JSON, XML, HTML). Это, конечно, не AJAX в полном смысле этого слова, то тоже выход.
Как пример, могу предложить решение с jQuery и PHP. Но это как-то скучно.
Решение 2: Flash как посредник
Этот способ уже более интересен. Flash может делать кроссдоменные запросы, при условии, если сам сервер позволяет флешу к нему обращаться. Для этого существует, опять же, своя политика безопасности, но она, в отличии от XmlHttpRequest-ой довольно гибкая — для разрешения запроса к серверу в его корне необходимо создать файл crossdomain.xml, в котором указать, какие сервера имеют право доступа. Простейший пример такого файла:
Ну а далее Flash-скрипт получает запрос от JS, делает кроссдоменный запрос, получает данные и отдает их обратно в JS-скрипт. А вот вам готовый скрипт и его модернизация, которые все это реализует.
Как сделать кроссдоменный запрос
Добавлено через 8 минут
даже вот так
Добавлено через 3 минуты
Комментарий модератора | |
|
Кроссдоменный ajax запрос
Здравствуйте. Возникла проблема при составлении ajax запроса на другой сервер. Задача я упростил.
Кроссдоменный запрос JSON
есть API с расписанием я делаю кросс-доменный запрос и он вроде как работает так как в хроме.
Кроссдоменный запрос (с Jquery или без)
Доброго времени суток уважаемые! Столкнулся с проблемой — необходимо проверить в браузере.
Как правильно сделать запрос к API ?
Привет. Вот простой запрос к API: https://emspost.ru/api/rest/?method=ems.test.echo Если его.
Как сделать запрос к transmission на javascript?
Коллеги, никогда не программировал на javascript и ajax. Сейчас изучаю эти технологии. Есть.
Как выполнить кросс-домен ajax в jQuery с помощью dataType ‘text’?
4 Radek [2011-08-23 10:13:00]
В моей функции javacript я называю это ajax. Он работает нормально, но только при доступе к веб-странице с сервера firebird . У меня такой же код на моем сервере testing . Ajax просит загрузить некоторые файлы, но только сервер Firebird имеет свои ip-регистры с нашими клиентами, чтобы иметь возможность scp там. Мне нужно сделать то же самое, если я получаю доступ к php файлам с сервера тестирования. Все серверы находятся внутри интрасети.
- можно ли использовать dataType text для этого?
- Нужно ли делать какие-либо изменения на стороне сервера?
Обновление 1
Мое маленькое веб-приложение восстанавливает базы данных, поэтому я могу выполнить их тестирование. Теперь я хочу улучшить его, чтобы я мог подключиться к нашим клиентам и загрузить конкретную резервную копию. Наш клиент разрешил только сервер firebird подключаться к своим сетям. Но у меня есть собственный сервер, посвященный testing . Поэтому каждый раз, когда я хочу загрузить базу данных, мне нужно подключиться firebird . Источник моего веб-приложения и папка со всеми резервными копиями монтируются в одно и то же место на обоих серверах firebird и testing . Прямо сейчас мое решение (для загрузки) работает, но только от firebird. Я работаю в основном только с сервером testing .
Обновление 2
Я делаю два вызова ajax. Один из них — чистый вызов jQuery (я предполагаю, что могу применить любое решение к этому), а другой — ajax-вызов от jsTree. Я создал новый вопрос для этого. Мне кажется, что I have to подходит для опции @zzzz b).
javascript jquery ajax cross-domain
4 ответа
1 Решение Baz1nga [2011-08-28 09:56:00]
У вас есть следующие варианты:
a) Вы используете тип jsonp в качестве типа данных, но это включает в себя внесение изменений на стороне сервера для передачи данных назад как json, а не как txt.. это изменение может быть таким же простым, как
а на стороне js вы используете это как response.text; Сказав, что если вы получаете текстовый файл для вашего файла из другого домена, я не уверен, насколько легко вам изменить код.
b) Другой вариант заключается в том, что вы пишете обработчик/конечную точку на своем сервере, то есть в вашем домене, который сделает запрос HTTP к этому третьему домену, получает файл, и вы отправляете файл обратно своему клиенту и фактически теперь ваш клиент разговаривает только с вашим доменом, и вы контролируете все. как и большинство вопросов yoyr, основанных на Ruby, вот пример:
вы можете найти более подробную информацию о том же здесь.
Надеюсь, что это поможет.
Чтобы выполнять перекрестные запросы домена, ваши варианты довольно ограничены. Как упоминалось @Mrchief, вы можете сделать серверный прокси-сервер и jsonp.
Основная идея CORS заключается в использовании пользовательских HTTP-заголовков для браузеру и серверу достаточно знать друг друга определить, будет ли запрос или ответ успешным или неудачным.
Для простого запроса, который использует GET или POST без пользовательских заголовки и чье тело является текстовым/обычным, запрос отправляется с дополнительный заголовок, называемый Origin. Заголовок Origin содержит начало (протокол, имя домена и порт) запрашивающей страницы, чтобы сервер может легко определить, должен ли он отвечать на ответ.
Вы можете найти некоторые живые примеры на этом сайте.
Вам нужно будет внести изменения на стороне сервера, чтобы принять запросы CORS. Поскольку у вас есть контроль над сервером, это не должно быть проблемой. Другой недостаток с CORS заключается в том, что он может быть несовместим со старыми браузерами. Итак, если некоторые из ваших основных аудиторий используют несовместимые браузеры, прокси-сервер на стороне сервера может быть для вас лучшим вариантом.
Я просто хочу предложить альтернативу.
Я не слишком уверен в настройке вашей сети, но если у вас есть доступ к DNS, возможно, это было бы проще всего, если бы вы просто предоставили своим серверам какой-либо произвольный субдомен того же домена. Что-то вроде www.foo.com для веб-сайта и firebird.private.foo.com для сервера Firebird. Таким образом, он становится перекрестным субдоменом вместо перекрестного домена. Затем где-то в вашем JavaScript на обеих страницах,
Этот джентльмен достиг этого решения здесь.
0 Ed Heal [2011-08-28 10:02:00]
Другая идея — использовать ваш веб-сервер в качестве прокси. Вам необходимо будет учитывать последствия для безопасности для этого маршрута.
Ajax-запрос
Материал из JQuery
url — адрес запроса.
settings — в этом параметре можно задать настройки для данного запроса. Задается с помощью объекта в формате . Ни одна из настроек не является обязательной. Установить настройки по умолчанию можно с помощью метода $.ajaxSetup().
Отличие от предыдущего варианта метода заключается лишь в том, что свойство url здесь является частью настроек, а не отдельным параметром.
Содержание
Список настроек
Имейте ввиду, что выполнение запросов в синхронном режиме может привести к блокировке страницы, пока запрос не будет полностью выполнен.
beforeSend относится к ajax-событиям. Поэтому если указанная в нем функция вернет false, ajax-запрос будет отменен.
Начиная с jQuery-1.5, beforeSend вызывается независимо от типа запроса.
Начиная с jQuery-1.5, в параметр complete можно передать не одну функцию, а массив функций. Все функции будут вызваны в той очередности, в которой заданы в этом массиве.
В качестве контекста можно задать DOM-элемент, который должен каким-либо образом сигнализировать о завершении запроса:
В случае запроса методом GET, строка с данными добавляется в конец url. Если данные задаются с помощью объекта, то он должен соответствовать формату: .
Событие error не определено для dataType равных script и JSONP.
Рекомендуется устанавливать значение параметраisLocal глобально — с помощью функциии $.ajaxSetup(), а не в настройках отдельных ajax-запросов.
Начиная с jQuery-1.5, указав в этом параметре false, вы предотвратите добавление в url дополнительного параметра. В этом случае необходимо явно установить значение свойства jsonpCallback. Например так: .
Начиная с jQuery-1.5, вы можете указать функцию в этом параметре, для того, чтобы обработать ответ сервера самостоятельно. В этом случае, указанная функция должна возвращать полученные от сервера данные (в указанной функции они будут доступны в первом параметре).
Функции, реагирующие на коды удачного выполнения запроса будут получать те же аргументы, что и функции-обработчики удачного выполнения запроса (указанные в параметре success), а функции, срабатывающие на коды ошибок, будут такими же, как и у error-функций.
Время отсчитывается с момента вызова функции $.ajax. Может случиться так, что в этот момент будет запущено несколько других запросов и браузер отложит выполнение текущего запроса. В этом случае timeout может завершиться, хотя фактически, запрос даже еще не был запущен.
В jQuery-1.4 и младше, при завершении времени ожидания, объект XMLHttpRequest перейдет в состояние ошибки и доступ к его полям может вызвать исключение. В Firefox 3.0+ запросы типа script и JSONP не будут прерваны при превышении времени ожидания. Они будут завершены даже после того как это время истечет.
В jQuery-1.5 свойство withCredentials не поддерживается нативным XMLHttpRequest и при кроссдоменном запросе это поле будет проигнорировано. Во всех следующих версиях библиотеки, это исправлено.
Обработчики событий
Настройки beforeSend, error, dataFilter, success и complete (их описание есть в предыдущем разделе) позволяют установить обработчики событий, которые происходят в определенные моменты выполнения каждого ajax-запроса.
beforeSend происходит непосредственно перед отправкой запроса на сервер. error происходит в случае неудачного выполнения запроса. dataFilter происходит в момент прибытия данных с сервера. Позволяет обработать "сырые" данные, присланные сервером. success происходит в случае удачного завершения запроса. complete происходит в случае любого завершения запроса.
Пример простого использования. Выведем сообщение при удачном выполнении запроса:
Начиная с jQuery-1.5, метод $.ajax() возвращает объект jqXHR, который помимо прочего реализует интерфейс deferred, что позволяет задавать дополнительные обработчики выполнения. Помимо стандартных для объекта deferred методов .done(), .fail() и .then(), с помощью которых можно устанавливать обработчики, в jqXHR реализованы .success(), .error() и .complete(). Это сделано для соответствия привычным названиям методов, с помощью которых устанавливаются обработчики выполнения ajax-запросов. Однако начиная с jQuery-1.8 эти три метода станут нежелательными для использования.
Для некоторых типов запросов, таких как jsonp или кроссдоменных GET-запросов, не предусматривается использование объектов XMLHttpRequest. В этом случае, передаваемые в обработчики XMLHttpRequest и textStatus будут содержать значение undefined.
Внутри обработчиков, переменная this будет содержать значение параметра context. В случае, если он не был задан, this будет содержать объект настроек.
Параметр dataType
Функция $.ajax() узнает о типе присланных сервером данных от самого сервера (средствами MIME). Кроме этого, существует возможность лично указать (уточнить), как следует интерпретировать эти данные. Это делается с помощью параметра dataType. Возможные значения этого параметра:
"xml" — полученный xml-документ будет доступен в текстовом виде. С ним можно работать стандартными средствами jQuery (также как и с документом html). "html" — полученный html будет доступен в текстовом виде. Если он содержит скрипты в тегах
Кросс-доменные ajax-запросы и причем здесь php
Однажды я писал статью как создавать встраиваемые виджеты на нативном javascript и php. И все бы хорошо, но в ней не затронул один момент. Такие виджеты использовать на собственном сайте можно, но интереснее создавать их для сторонних ресурсов. Но в таком случае нужные данные браузер должен подгружать с другого домена - это и есть кросс-доменные ajax-запросы.
С точки зрения фронтенд-программистов кросс-доменные запросы ничем не отличаются от обычных. А вот на бекенде разница есть. Почему с ними не все так просто и как их реализовать - об этом читайте в статье.
Пробуем получить данные с другого домена
Для простоты рассмотрим get-запросы. Допустим, на сервере лежит некий html-файлик, который нам край как нужно загрузить ajax-ом с другого домена. Пусть это файл https://webdevkin.ru/examples/cross_domain/template.html. Откройте его и убедитесь, что он действительно доступен - вот ссылка (откроется в новой вкладке). Это обычный div с текстом "content from template.html".
А теперь давайте получим эту html-ку ajax-ом прямо из консоли браузера.
Не будем париться с нативным javascript-ом, а дернем запрос с помощью jQuery.get() и выведем в консоль то, что получили в ответ с сервера.
Откройте прямо сейчас developer tools в браузере и на вкладке console выполните этот запрос.
Вы увидите примерно следующее
Все замечательно, отправили запрос, получили ответ. Казалось бы, что может быть проще? А теперь зайдите на любой другой сайт, где подключен jQuery и попробуйте проделать то же самое. Только не на https-сайт, почему - узнаете в конце статьи.
Я, например, проверял запросы на футбольном сайте bombardir.ru. И заодно подивился, какой только дряни не вываливается в консоль даже на таких достаточно известных сайтах. Впрочем, разговор не про это.
Выполните запрос с другого домена и Вы увидите в консоли уже не такую благостную картину. Говорит, невозможно загрузить, данных нет и вообще печаль.
Если откроете вкладку Network и найдете там соотвествующий запрос, то увидите, сервер даже вернул нам 200 ОК А содержимого файла нет. В чем подвох?
Что пошло не так и каково будет решение
Подвох в том, что политика интернетов не разрешает браузерам вытаскивать данные с каких угодно ресурсов. Кроме тех случаев, когда эти ресурсы сами заинтересованы в раздаче конкретных данных.
Наш случай именно такой. Чтобы дать разрешение на использование html-файлика откуда угодно, нужно при запросе оного файла отправлять http-заголовок Access-Control-Allow-Origin: *
Теперь вопрос, как это сделать. Если у Вас (или же у админов) есть доступ к nginx, то одним способом будет настроить прокидывание этого заголовка средствами веб-сервера. Вы идете к админам с соответствующей просьбой или гуглите сами нужные конфиги для Вашего веб-сервера.
Если же этого доступа нет, как например, у практически любого хостинг-провайдера на недорогом тарифе, то нужно выкручиваться самостоятельно. И здесь на помощь приходит php. Идея в том, чтобы закинуть нашу html-ку в php-файл, который и прокинет заголовок, и отдаст нужное содержимое.
Получится так, создаем файл template.php и первой строкой запишем php-команду
А дальше html-код
То есть содержимое template.php будет таким, не забудьте про php-шные вопросы и скобки
Файл на webdevkin-е создан и лежит здесь (откроется в новой вкладке). Давайте теперь попробуем запросить его с другого домена и посмотрим, что будет
Как видно, все работает прекрасно - файл загружен!
Заглянем на вкладку Network.
Обратите внимание, в блоке Response Headers появился интересующий нас заголовок Access-Control-Allow-Origin: *
В целом статья закончена. Осталось собрать мысли в кучу и добавить еще немного информации.
Обобщаем и подводим итоги
- 1. Нельзя просто так запросить ajax-ом любой ресурс с другого домена
- 2. Отправляйте заголовок Access-Control-Allow-Origin для всех ресурсов, к которым нужен доступ откуда угодно
- 3. Делайте это средствами веб-сервера или php
- 4. На php этот заголовок отправляется командой header('Access-Control-Allow-Origin: *')
- 5. Access-Control-Allow-Origin: * - разрешить доступ всем доменам, Access-Control-Allow-Origin: site.ru - только домену site.ru
- 6. Access-Control-Allow-Origin отправляется в самом начале php-файла, еще до вывода других данных (как впрочем, и любые другие http-заголовки)
- 7. "Ресурс" - это не только файл с html-разметкой, но и любой url, к которому идет ajax-запрос, например, получение json-данных или post-запрос на добавление строки в таблицу БД
И последнее, вынес отдельно. Я не зря просил выполнять запросы именно с http-сайта. С https не получится подгрузить данные с http по другой причине - mixed content. А webdevkin.ru пока что http-сайт (updated: уже нет, перенес webdevkin.ru на https)
Вот что увидите в консоли, попытавшись выполнить тот же запрос с любого https-сайта. Поэтому если Вы собираетесь заниматься встраиваемыми виджетами или чем-то подобным, Вам обязательно нужно поставить ssl-сертификат на своем сайте.
jQuery.ajax()
Выполняет асинхронный HTTP (Ajax) запрос
version added: 1.5 jQuery.ajax( url [, settings] )
url
Тип: Строка
URL адрес, на который будет отправлен Ajax запрос
settings
Тип: Объект
Набор параметров вида ключ / значение, которые настраивают запрос Ajax. Все настройки опциональны. По умолчанию настройки берутся из $.ajaxSetup(). Ниже приведен полный список всех настроек.
version added: 1.0 jQuery.ajax( settings )
settings
Тип: Объект
Набор параметров вида ключ / значение, которые настраивают запрос Ajax. Все настройки опциональны. По умолчанию настройки берутся из $.ajaxSetup().
settings:
логический | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
логический | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
функция или массив | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
логический | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
объект или строка | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
функция или массив | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
логический | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
логический | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
логический | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
строка или функция | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
логический | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
функция или массив | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
логический | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Параметр | Описание | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
url | Строка, содержащая URL адрес, на который отправляется запрос. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
settings | Набор пар ключ/значение, которые настраивают запрос AJAX. Все параметры являются необязательными. Допускается, но не рекомендовано установить значение по умолчанию для любого параметра с использованием метода $.ajaxSetup(). Метод $.ajax() поддерживает следующие параметры: accepts (по умолчанию: зависит от dataType). Тип: PlainObject . async (по умолчанию: true ). Тип: Boolean . Тип: Function ( jqXHR jqXHR, PlainObject settings ). cache (по умолчанию: true , для dataType "script" и "jsonp" false ). Тип: Boolean . Тип: Function ( jqXHR jqXHR, String textStatus ). Тип: PlainObject . contentType (по умолчанию: "application/x-www-form-urlencoded; charset=UTF-8"). Тип: Boolean , или String . Тип: PlainObject . Значения по умолчанию: crossDomain (по умолчанию: false для запросов внутри того же домена, true для кроссдоменных запросов). Тип: Boolean . Тип: PlainObject , или String , или Array . Тип: Function ( String data, String type ) => Anything . dataType (по умолчанию: xml, json, script, или html ). Основные типы (результат передается в качестве первого аргумента в функцию обратного вызова success):
Cross Domain AJAX RequestA common problem for developers is a browser to refuse access to a remote resource. Usually, this happens when you execute AJAX cross domain request using jQuery Ajax interface, Fetch API, or plain XMLHttpRequest. As result is that the AJAX request is not performed and data are not retrieved. Figure 1. The same-origin policy restriction in effect Same-Origin PolicyThis is a security policy who defines the rules of how a web page can access an external resource (e.g. fonts, AJAX requests). Under the same-origin policy, web browsers do not permit a web page to access resources who origin differ than that of the current page. The origin is cons >Cross-origin resource sharing or simply CORS . Cross-Origin Resource SharingCORS is a mechanism that defines a procedure in which the browser and the web server interact to determine whether to allow a web page to access a resource from different origin. Figure 2. Cross domain ajax request When you do a cross-origin request, the browser sends Origin header with the current domain value. When the server receives the request, check whether the origin header is within the allowed list, and sends a response with Access-Control-Allow-Origin If you want to allow access for all, use a wildcard '*' AJAX cross domain request1. Simple request
This is how the simple cross domain ajax request should looks like: 2. Preflighted requests 3. Request with credentials 4. The Response
Browser supportChrome 3+, Firefox 3.5+, IE 10+, Opera 12+, Safari 4+ Editor's Note: This post was originally published in February 2015 and has been revised and updated for accuracy and comprehensiveness. Использование AjaxВ предыдущей статье мы познакомились с прямыми методами jQuery для работы с Ajax (такими как get(), post() и load()). В этой статье описан низкоуровневый программный интерфейс . Казалось бы, термин низкоуровневый указывает на то, что вы получаете доступ к скрытым возможностям механизма запросов, но это не совсем так. Описываемые здесь методы менее удобны по сравнению с рассмотренными ранее, однако ценой небольших дополнительных усилий запрос можно сконфигурировать так, чтобы он в точности соответствовал вашим потребностям, чего не всегда удается добиться с помощью прямых или вспомогательных методов. Простые Ajax-запросыСоздавать запросы с помощью низкоуровневого API не намного сложнее, чем с помощью прямых или вспомогательных методов. Разница состоит в том, что такой подход позволяет контролировать многие другие аспекты запроса и получать о выполняющемся запросе гораздо больше информации. Центральное место в низкоуровневом API занимает метод ajax(), простой пример использования которого приведен ниже (здесь используется исходный файл и файл mydata.json, описанные в предыдущей статье): Аргументами метода ajax() являются запрашиваемый URL и объект отображения данных, свойства которого определяют набор пар "ключ-значение", каждая из которых определяет некий параметр запроса. Здесь передаваемый методу ajax() объект содержит только один параметр, success, задающий функцию, которая будет вызываться в случае успешного выполнения запроса. В данном примере мы запрашиваем у сервера файл mydata.json и используем его вместе с шаблоном данных для создания элементов и вставки их в документ, как это делалось в предыдущей статье с помощью прямых методов. По умолчанию метод ajax() создает HTTP-запрос GET, т.е. данный пример эквивалентен использованию методов get() и getJSON(). Объект jqXHRМетод ajax() возвращает объект jqXHR, который можно использовать для получения подробной информации о запросе и с которым можно взаимодействовать. Объект jqXHR представляет собой оболочку объекта XMLHttpRequest, составляющую фундамент браузерной поддержки Ajax. При выполнении большинства операций Ajax объект jqXHR можно просто игнорировать, что я и рекомендую делать. Этот объект используется в тех случаях, когда необходимо получить более полную информацию об ответе сервера, чем та, которую удается получить иными способами. Кроме того, его можно использовать для настройки параметров Ajax-запроса, но это проще сделать, используя настройки, доступные для метода ajax(). Свойства и методы объекта jqXHR описаны в таблице ниже:
Объект jqXHR встречается в нескольких местах кода. Сначала он используется для сохранения результата, возвращаемого методом ajax(), как показано в примере ниже: В этом примере мы сохраняем результат, возвращаемый методом ajax(), а затем используем метод setInterval() для вывода информации о запросе каждые 100 мс. Использование результата, возвращаемого методом ajax(), не изменяет того факта, что запрос выполняется асинхронно, поэтому при работе с объектом jqXHR необходимо соблюдать меры предосторожности. Для проверки состояния запроса мы используем свойство readyState (завершению запроса соответствует значение 4) и выводим ответ сервера на консоль. Для данного сценария консольный вывод выглядит так (в вашем браузере он может выглядеть несколько иначе): Я использую объект jqXHR лишь в редких случаях и не делаю этого вообще, если он представляет собой результат, возвращаемый методом ajax(). Библиотека jQuery автоматически запускает Ajax-запрос при вызове метода ajax(), и поэтому я не считаю возможность настройки параметров запроса сколько-нибудь полезной. Если я хочу работать с объектом jqXHR (как правило, для получения дополнительной информации об ответе сервера), то обычно делаю это через параметры обработчика событий, о которых мы поговорим далее. Они предоставляют мне информацию о состоянии запроса, что избавляет от необходимости выяснять его. Задание URL-адреса запросаОдним из наиболее важных доступных параметров является параметр url, позволяющий указать URL-адрес для запроса. Можно использовать этот параметр как альтернативу передаче URL-адреса в качестве аргумента метода ajax(), как показано в примере ниже: Создание POST-запросаДля задания требуемого типа запроса, который необходимо выполнить, используется параметр type. По умолчанию выполняются GET-запросы, как в предыдущем примере. Пример использования метода ajax() для создания POST-запроса и отправки данных формы на сервер приведен ниже: Здесь я не буду подробно описывать этот пример, т.к. мы его рассмотрели подробно в предыдущей статье (только с использованием метода post()). Отмечу только, что здесь дополнительно к type мы использовали еще несколько параметров. Для указания цели POST-запроса используется описанный ранее параметр url. Пересылаемые данные указываются с помощью параметра data, значение которого устанавливается с помощью метода serialize(), описанного в предыдущей статье. Тип данных, получаемых от сервера указывается в параметре dataType. Работа с событиями AjaxНесколько параметров позволяют указывать функции для обработки событий, которые могут запускаться на протяжении жизненного цикла Ajax-запроса. Именно таким способом вы будете указывать функции обратного вызова, играющие столь важную роль в Ajax-запросах. С одной из них вы уже познакомились при рассмотрении параметра success в предыдущем примере. Список параметров, связанных с событиями, вместе с их краткими описаниями приведен в таблице ниже:
Обработка успешных запросовВ примерах выше, при использовании параметра success, в вызове функции были опущены два аргумента — сообщение, описывающее результат запроса, и объект jqXHR. Пример использования функции, которая принимает эти аргументы, приведен ниже: Аргумент status — это строка, описывающая исход запроса. Функция обратного вызова, которую мы задаем, используя параметр success, выполняется лишь для успешных запросов, и поэтому значением данного аргумента обычно является success. Исключением является случай, когда вы используете параметр ifModified, описанный далее. Функции обратного вызова для всех событий Ajax следуют одному и тому же образцу, но наибольшую пользу этот аргумент приносит в случае ряда других событий. Последний аргумент — это объект jqXHR. Вы не должны выяснять состояние запроса, прежде чем начать работу с этим объектом, поскольку знаете, что функция выполняется лишь тогда, когда запрос завершается успешно. В этом примере объект jqXHR используется для получения информации о состоянии запроса и заголовках, которые сервер включил в ответ, а также для вывода этой информации на консоль. В данном случае результат имеет следующий вид (в зависимости от того, какой сервер вы используете, у вас может быть другой набор заголовков): Обработка ошибокПараметр error используется для указания функции, которая должна вызываться при неудачном завершении запроса. Соответствующий пример приведен ниже: Здесь запрашивается отсутствующий на сервере файл NoSuchFile.json, и поэтому запрос заведомо не сможет быть выполнен, в результате чего будет вызвана функция, заданная с помощью параметра error. Аргументами этой функции являются объект jqXHR, а также сообщение о состоянии ошибки и сообщение об ошибке, полученное в ответе сервера. Внутри этой функции в документ добавляется элемент div, отображающий значения аргументов status и errorMsg, как показано на рисунке: Настройка параметров запросов перед их отправкойПараметр beforeSend позволяет задать функцию, которая будет вызываться перед отправкой запросов. Это позволяет сконфигурировать запрос в последнюю минуту, добавляя или заменяя параметры, переданные методу ajax() (что может быть особенно полезным, если для множества запросов используется один и тот же объект, содержащий необходимые значения параметров). Пример использования такого подхода представлен ниже: Аргументами указанной функции являются объект jqXHR (который может пригодиться для настройки заголовков запроса или отмены запроса, прежде чем он будет отправлен) и объект, содержащий параметры, переданные методу ajax(). В данном примере URL-адрес для Ajax-запроса задается с помощью параметра beforeSend. Задание нескольких обработчиков событийВ предыдущих примерах мы реагировали на наступление событий, связанных с Ajax-запросами, вызовом одной функции, но в параметрах success, error, complete и beforeSend можно задавать массив функций, каждая из которых будет выполняться при запуске соответствующего события. Простой пример этого приведен ниже: В этом примере для параметра success задан массив, состоящий из двух функций, одна из которых использует данные для добавления элементов в документ, а вторая выводит информацию на консоль. Настройка контекста для событийПараметр context позволяет указать элемент, который будет назначен переменной this, когда будет вызван обработчик события. Это может быть использовано для обращения к целевым элементам в документе без необходимости их выбора в функции-обработчике. Соответствующий пример приведен ниже: Здесь параметр context устанавливается на объект jQuery, содержащий элементы h1 документа. В функции, определяемой параметром complete, мы выделяем рамкой выбранные элементы (в данном случае — элемент, поскольку в документе есть только один элемент h1) путем вызова метода css() для объекта jQuery (на который ссылаемся через this). Цвет рамки определяется на основании состояния запроса. С помощью параметра context можно установить в качестве контекста любой объект, и ответственность за выполнение только допустимых для этого объекта операций лежит на вас. Например, если вы задаете в качестве контекста элемент HTMLElement, то до того, как вызывать для него какие-либо методы jQuery, вы должны передать этот объект функции $(). Настройка базовых параметров Ajax-запросовСуществует группа параметров, с помощью которых можно выполнить базовую настройку Ajax-запроса (некоторые из них, url и type, мы рассмотрели выше). Из всех доступных параметров они представляют наименьший интерес, и их имена в основном говорят сами за себя. Параметры, о которых идет речь, приведены в таблице ниже:
Задание тайм-аутов и заголовковО том, что выполняются Ajax-запросы, пользователи часто даже не догадываются, и поэтому указание допустимой длительности тайм-аута — неплохая идея, поскольку это избавит пользователей от томительного ожидания завершения какого-то неведомого для них процесса. Пример задания тайм-аута для запроса приведен ниже: В этом примере параметр timeout устанавливает максимальную длительность тайм-аута, равную 5 сек. Если запрос за это время не будет выполнен, то вызовется функция, заданная с помощью параметра error, и будет выведен код ошибки, определяемый параметром status. Таймер запускается сразу же после передачи запроса браузеру, и большинство браузеров налагают ограничения на количество одновременно выполняющихся запросов. Это означает, что существует риск того, что к моменту истечения тайм-аута запрос даже не будет запущен. Чтобы избежать этого, необходимо располагать сведениями об ограничениях браузера, а также об объеме и ожидаемой длительности любых других выполняющихся Ajax-запросов. Дополнительно в этом примере ниже используется параметр headers, с помощью которого в запрос добавляется заголовок. Для указания заголовков используется объект отображения данных. Используемый здесь заголовок может быть полезным для создания веб-приложений, поддерживающих архитектурный стиль REST, если только сервер правильно его распознает. Использование дополнительных конфигурационных параметровВ следующих разделах описаны наиболее полезные и заслуживающие внимания дополнительные параметры, применимые к Ajax-запросам. Обычно они редко используются, но в случаях, когда в них возникает потребность, они оказываются незаменимыми. Эти параметры позволяют осуществлять точную настройку взаимодействия jQuery с Ajax. Создание синхронных запросовУправление режимом выполнения запросов осуществляется с помощью параметра async. Значение true, используемое для этого параметра по умолчанию, означает, что запрос будет выполняться в асинхронном режиме, тогда как значению false соответствует синхронный режим. При синхронном выполнении запроса метод ajax() ведет себя, как обычная функция, и браузер переходит к выполнению других инструкций сценария лишь после того, как закончится выполнение запроса. Игнорирование данных, оставшихся неизменнымиС помощью параметра ifModified можно обеспечить получение данных лишь в том случае, если с момента последнего запроса они были изменены. Такое поведение определяется заголовком Last-Modified. Благодаря этому удается избежать бесполезной пересылки данных, которая не даст пользователю никакой новой информации по сравнению с той, которой он уже располагает. По умолчанию параметр ifModified имеет значение false, указывающее jQuery на необходимость игнорирования заголовка Last-Modified и предоставления данных в любом случае. Пример использования этого параметра приведен ниже: В этом примере значение параметра ifModified устанавливается равным true. Функция success вызывается всегда, но если с того момента, когда содержимое запрашивалось в последний раз, оно не изменилось, то аргумент data будет иметь значение undefined, а аргумент status — значение notmodified. В данном случае выполняемые действия определяются значением аргумента status. Если значением этого аргумента является success, то аргумент data используется для добавления элементов в документ. Если же аргумент status имеет значение notmodified, то мы используем метод css() для выделения рамкой элементов, которые уже имеются в документе. В ответ на событие click, связанное с кнопкой, вызывается метод ajax(). Это дает возможность многократно повторять один и тот же запрос, чтобы продемонстрировать влияние параметра ifModified, как показано на рисунке: Каким бы полезным ни был этот параметр, я рекомендую использовать его с осторожностью. Если отправка запроса является следствием действий пользователя (например, щелчка на кнопке), то существует вероятность того, что пользователь щелкнул на кнопке, поскольку предыдущий запрос не был выполнен так, как ожидалось. Представьте, что вы запрашиваете данные, но в методе, указанном в параметре success, содержится ошибка, которая препятствует правильному обновлению содержимого документа. Тогда вашим следующим действием будет попытка щелкнуть на кнопке еще раз, чтобы добиться ожидаемого результата. Непродуманно используя параметр ifModified, можно проигнорировать действия пользователя, вынуждая его предпринимать более серьезные действия для устранения проблемы. Обработка кода ответаПараметр statusCode позволяет выбирать варианты дальнейших действий в зависимости от кода ответов на HTTP-запросы. Его можно использовать либо вместо параметров success и error, либо в дополнение к ним. Пример самостоятельного использования параметра statusCode приведен ниже: Здесь параметр statusCode задан в виде объекта, устанавливающего связь между кодами ответов на HTTP-запросы и соответствующими им функциями, которые должны быть выполнены на сервере. Какие именно аргументы передаются функциям, зависит от того, отражает ли код ответа успешное выполнение запроса или ошибку. Если код (например, 200) соответствует успешному запросу, то аргументы совпадают с теми, которые передавались бы функции, определяемой параметром success. В противном случае (например, при коде ответа 404, означающем, что запрашиваемый файл не найден) аргументы совпадают с теми, которые передавались бы функции, определяемой параметром error. Как видите, это средство не дает непосредственной информации о кодах ответа. Я часто пользуюсь им в процессе отладки взаимодействия браузера с сервером, обычно для того, чтобы выяснить, почему jQuery ведет себя не так, как мне хотелось бы. При этом я использую параметр statusCode в дополнение к параметрам success и error и вывожу информацию на консоль. Если эти параметры используются совместно, то сначала будут выполнены функции success и error, а затем уже — функции, определяемые параметром statusCode. Предварительная очистка ответных данныхС помощью параметра dataFilter можно задать функцию, которая будет вызвана для предварительной очистки данных, возвращаемых сервером. Это средство незаменимо в тех случаях, когда пересылаемые сервером данные не совсем вас устраивают либо из-за того, что отформатированы неподходящим образом, либо из-за того, что среди них есть данные, которые вы не хотите обрабатывать. Это средство мне очень помогает при работе с серверами Microsoft ASP.NET, присоединяющими лишние данные к данным JSON. Удаление таких данных с помощью параметра dataFilter требует лишь минимальных усилий. Пример использования параметра dataFilter приведен ниже: Функции передаются данные, полученные с сервера, и значение параметра dataType. Если параметр dataType не используется, то второму аргументу присваивается значение undefined. Ваша задача заключается в том, чтобы вернуть отфильтрованные данные. В этом примере предмет нашего внимания — данные в формате JSON: Для повышения иллюстративности примера в нем выполняются некоторые дополнительные операции. Во-первых, данные JSON преобразуются в массив JavaScript с помощью метода jQuery parseJSON. Затем из массива удаляется первый элемент с помощью метода shift(), а порядок следования остальных его элементов обращается с помощью метода reverse(). Все, что требуется от функции, — вернуть строку, и поэтому мы вызываем метод JSON.stringify(), зная, что jQuery преобразует данные в объект JavaScript, прежде чем вызвать функцию success. В данном примере была продемонстрирована возможность удаления элемента из массива, однако, в зависимости от ситуации, мы могли бы выполнить любой другой вид обработки. Конечный результат представлен на рисунке: Управление преобразованием данныхРассмотрение одной из самых любимых своих настроек я приберег напоследок. Должно быть, вы обратили внимание, что при получении определенных типов данных jQuery автоматически выполняет некоторые удобные преобразования. Например, получая данные JSON, jQuery предоставляет функцию success, использующую объект JavaScript, а не исходную необработанную строку JSON. Для управления подобными преобразованиями используется параметр converters. Значением этого параметра является объект, устанавливающий соответствие между типами данных и функциями, используемыми для их обработки. В примере ниже показано, как использовать этот параметр для автоматического преобразования HTML-данных в объект jQuery: В этом примере регистрируется функция для типа данных text html. Обратите внимание на пробел между компонентами указываемого MIME-типа (в отличие от формы записи text/html). Функция принимает данные, полученные от сервера, и возвращает преобразованные данные. В этом случае преобразование данных заключается в передаче HTML-фрагмента, содержащегося в файле flowers.html, функции $() и возврате результата. Отсюда следует, что к объекту, передаваемому в качестве аргумента data функции success, применимы обычные методы jQuery. Работая с преобразователями данных, можно слишком увлечься. Я всегда стараюсь избегать соблазна делать с помощью этих функций больше, чем следует. Например, иногда меня так и тянет применить к данным JSON шаблон и передать обратно полученные в результате HTML-элементы. И хотя этот прием очень удобен, он сослужит плохую службу, если кто-то другой будет пытаться расширить ваш код или, например, вам самому впоследствии потребуется организовать интенсивную обработку данных для получения их в исходной форме. Настройка и фильтрация Ajax-запросовПосле того как вы познакомились с методом ajax() и доступными для работы с ним параметрами, мы можем рассмотреть несколько дополнительных методов, предоставляемых jQuery для упрощения настройки запросов. Определение параметров, используемых по умолчаниюМетод ajaxSetup() позволяет установить значения параметров, которые будут применяться по умолчанию во всех Ajax-запросах, тем самым освобождая вас от необходимости настраивать параметры при каждом запросе. Пример использования этого метода приведен ниже: Метод ajaxSetup() вызывается с помощью функции jQuery $ аналогично тому, как это делалось в случае вызова метода ajax(). Аргументом метода ajaxSetup() является объект, содержащий значения параметров, которые вы хотите использовать по умолчанию для всех Ajax-запросов. В этом примере мы устанавливаем значения по умолчанию для параметров timeout, global, error и converters. После того как был вызван метод ajaxSetup(), нам остается определить значения лишь те значения параметров, которые мы хотим изменить, или те, которые не предоставляются по умолчанию. Это обеспечивает значительную экономию времени в тех случаях, когда приходится делать множество запросов с одинаковыми значениями параметров. Фильтрация запросовМетод ajaxSetup() определяет базовые значения конфигурационных параметров, применимые ко всем запросам Ajax. Возможности динамической настройки параметров для отдельных Ajax-запросов обеспечиваются методом ajaxPrefilter(). Пример использования этого метода приведен ниже: Указанная вами функция будет выполняться для каждого нового Ajax-запроса. Аргументами, передаваемыми функции, являются параметры запроса (включая любые значения по умолчанию, установленные вами с помощью метода ajaxSetup()), а также исходные параметры, переданные методу ajax() (исключая любые значения по умолчанию) и объекту jqXHR запроса. Мы вносим изменения в объект, передаваемый в качестве первого аргумента, как показано в примере. В данном сценарии, если среди параметров, передаваемых методу ajax(), присутствует параметр dataType, то длительность тайм-аута устанавливается равной двум секундам. Чтобы предотвратить отправку всех остальных запросов, для объекта jqXHR вызывается метод abort(). |