Технология CORS для XHR в Internet Explorer 10
Четвертая версия платформы Internet Explorer 10 упрощает построение межсайтовых сценариев, согласованно работающих в разных браузерах, благодаря поддержке технологии CORS (Cross-Origin Resource Sharing) для XMLHttpRequest (XHR). Технология CORS для XHR делает общий доступ сайтов к данным простым и гибким. В большинстве базовых сценариев технология CORS позволяет создавать источники данных, доступные с любого сайта, и с помощью нескольких небольших настроек вы можете ограничить перечень разрешенных сайтов, реализовать поддержку изменения данных и даже включить проверку подлинности. Чаще всего технология CORS обеспечивает безопасность существующих сайтов посредством запроса участия сервера.
Простой XHR-запрос о происхождении
Давайте рассмотрим, чем запрос XHR о происхождении отличается от запроса того же источника. По отношению к скрипту единственное отличие состоит в URL-адресе, передаваемом методу Open. Например, предположим, что мы работаем со скриптом, который вызывает список фотоальбомов.
Традиционный XHR
// Script running on http://photos.contoso.com
var xhr = new XMLHttpRequest();
xhr.onerror = _handleError;
xhr.onload = _handleLoad;
xhr.open("GET", "/albums", true);
xhr.send();
Теперь мы хотим получить доступ к списку альбомов из другого источника. Другой источник может быть совершенно другим доменом или другим узлом с таким же базовым доменом. В любом случае для того, чтобы браузер автоматически отправил запрос CORS, достаточно просто навести с другого сайта указатель на полный URL-адрес.
XHR с поддержкой CORS
// Script running on http://www.contoso.com
var xhr = new XMLHttpRequest();
xhr.onerror = _handleError;
xhr.onload = _handleLoad;
xhr.open("GET", "http://photos.contoso.com/albums", true);
xhr.send();
Сайты могут предоставлять альтернативу для более старых браузеров, разместив ее в средстве обнаружения компонентов. Наилучший подход заключается в проверке свойства «withCredentials
», так как оно непосредственно связано с поддержкой CORS для XHR.
XHR с поддержкой CORS и средством обнаружения компонентов
// Script running on http://www.contoso.com
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
xhr.onerror = _handleError;
xhr.onload = _handleLoad;
xhr.open("GET", "http://photos.contoso.com/albums", true);
xhr.send();
} else {
// Fallback behavior for browsers without CORS for XHR
}
На данном этапе наш клиентский код отправляет запрос CORS непосредственно на сайт «http://photos.contoso.com», однако этот запрос завершается сбоем и не возвращает никаких данных. Данный сбой происходит потому, что сервер еще не принимает участия. Быстро ознакомившись с информацией, представляемой средствами разработчика, можно понять причину ошибки.
Здесь мы видим, что сервер должен отправить в ответе заголовок «Access-Control-Allow-Origin
». В данном сценарии мы не открываем альбомы для доступа с любого сайта, а хотим разрешить доступ исключительно с сайта «http://www.contoso.com
». Для этого требуется разрешить серверу идентифицировать источник запроса. Анализ исходящего запроса позволяет выявить новый заголовок, содержащий требуемую информацию — «Origin
».
Заголовки простых запросов CORS
GET http://photos.contoso.com/albums HTTP/1.1
Origin: http://www.contoso.com
...
С помощью указанной информации сервер может ограничивать доступ любым набором сайтов. Если сервер всегда добавляет заголовок «Access-Control-Allow-Origin
» со значением «*», то доступ будет предоставляться всем сайтам. Для данного сценария сервер должен проверить источник и затем установить «Access-Control-Allow-Origin
», чтобы разрешить только «http://www.contoso.com
».
Заголовки простых ответов CORS
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.contoso.com
...
Получив указанные выше обновления, наш клиент «http://www.contoso.com
» теперь может осуществить доступ к спискам альбомов с сервера по адресу «http://photos.contoso.com
».
XHR-запрос о происхождении с предварительным запросом
Рассмотренные ранее «простые» запросы CORS отлично подходят для базовых сценариев с доступом «только для чтения», таких как загрузка фотоальбома. Для реализации следующего этапа, заключающегося в межсайтовом изменении данных, требуется провести определенную работу на сервере. Например, предположим, что мы добавляем код в клиент для создания нового альбома.
var xhr = new XMLHttpRequest();
xhr.onerror = _handleError;
xhr.onload = _handleLoad;
xhr.open("PUT", "http://photos.contoso.com/albums", true);
xhr.send(JSON.stringify({ name: "New Album" }));
Выполнение в исходном виде не дает результата. Анализ сетевого трафика позволяет выявить, что отправляется не тот запрос, который нами ожидался.
В действительности браузер отправляет так называемый предварительный запрос. Предварительные запросы отправляются перед запросами, которые могут вызвать изменение данных на сервере. Такие запросы выявляются по наличию сложных свойств, как определено в спецификации CORS. Диапазон этих свойств варьируется от отдельных HTTP-методов, например «PUT
», до настраиваемых HTTP-заголовков. Браузеры отправляют предварительные запросы, чтобы запросить у сервера разрешение на отправку непосредственного запроса. В данном примере браузер проверяет, разрешен ли запрос «PUT
».
Предварительный запрос
OPTIONS http://photos.contoso.com/albums HTTP/1.1
Origin: http://www.contoso.com
Access-Control-Request-Method: PUT
...
Чтобы браузер смог отправить непосредственный запрос, требуется внести некоторые изменения на сервере. Мы снова обращаемся к средствам разработчика для получения дополнительной информации.
Первый этап заключается в том, чтобы заставить сервер распознавать предварительный запрос «OPTIONS
» отдельно от других запросов для одного и того же URL-адреса. Когда сервер проверяет предварительный запрос, подтверждая, что «Access-Control-Request-Method
» запрашивается для «PUT
» из разрешенного источника, он отправляет соответствующее утверждение посредством заголовка «Access-Control-Allow-Methods
».
Предварительный ответ
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.contoso.com
Access-Control-Allow-Methods: PUT
...
После отправки предварительного запроса и получения соответствующего утверждения выполняется непосредственный запрос.
Непосредственный запрос
PUT http://photos.contoso.com/albums HTTP/1.1
Origin: http://www.contoso.com
...
На данном этапе технические аспекты добавления альбома выполнены, но код клиента не получит сведения об этом, пока сервер не отправит правильный ответ. Поэтому сервер по-прежнему должен включить «Access-Control-Allow-Origin
» в ответ.
Непосредственный ответ
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.contoso.com
...
С помощью этого кода клиент может добавить источники происхождения нового альбома и распознать, было ли это действие успешно выполнено.
Последующие шаги
Связывание CORS с другими компонентами новой платформы позволяет реализовать интересные сценарии. Одним из примеров является Тест межсайтовой отправки, который отслеживает происхождение отправки файлов с использованием CORS, XHR, FileAPI и событий Progress.
— Тони Росс (Tony Ross), руководитель программы, Internet Explorer