AJAX-запросы между доменами

Открыл сервис предпросмотра Markdown, порадовался за себя, но не заметил одной ошибки. Точнее, заметил, но не сразу. Через обычный POST всё шло славненько, а вот AJAX-запросы с других доменов не работали. Здесь я расскажу как сделать AJAX-сервис на вашем сайте действительно публичным.

Погуглив, нашёл ряд статеек на тему кроссдоменных запросов. Один из способов - это создание прокси на родном сервере и далее Curl'ом передавать данные и возвращать ответ. Не вариант, если уж я решил сделать публичный сервис. Нашёл интересные хаки, но опять же, не для моих нужд. И наконец наткнулся на термин CORS.

В прекрасном, но чересчур подробном указании от W3C я долго не мог понять о каких заголовках идёт речь и много времени потерял, увлёкшись, видимо, процессом поиска, а не чтения. Чуть позже, разобравшись что ищу, я вернулся и докурил этот в целом полезный, мануал. Больше всего понравилась статейка от developer.mozilla.org которая без лишней воды описывает реализацию в двух вариантах - Simple и Preflighted. К слову, у меня заработал только Preflighted, уж не знаю чем простой не угодил. И так, в чём он заключается.

Делая первый запрос к серверу, клиент сначала спрашивает разрешения посредством OPTIONS-запроса. В ответ, сервер должен заголовками сигнализировать о своей открытости для общения. Для этого понадобится взять пару заголовков из запроса и вставить их в заголовки ответа. На PHP это выглядит так:

$headers = apache_request_headers();
$headers = array_change_key_case($headers, CASE_LOWER);        // чтобы не было непоняток и разночтений
header('Access-Control-Allow-Origin',  @$headers['origin']);   // разрешаем хост который указан Origin
header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');  // нужное подчеркнуть или оставить как есть
header('Access-Control-Allow-Headers', @$headers['access-control-request-headers']); // это должно быть как в запросе
header('Access-Control-Max-Age', '600');                       // время в секундах

Или вот вариант для Symfony, вставляем в нужный контроллер, например apps/frontend/modules/test/actions/actions.class.php:

$this->getResponse()->setHttpHeader('Access-Control-Allow-Origin',  $request->getHttpHeader('origin') );
$this->getResponse()->setHttpHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
$this->getResponse()->setHttpHeader('Access-Control-Allow-Headers', $request->getHttpHeader('access-control-request-headers') );
$this->getResponse()->setHttpHeader('Access-Control-Max-Age', '600');

Клиент получит от сервера эти заголовки, запомнит что ему разрешено делать POST-запросы и совершит сие действо. Данный механизм реализован в популярных браузерах и менять в своих javascript ничего не придётся. Для теста советую закомментировать последнюю строчку, чтобы отлавливать OPTIONS-запросы не раз в 10 минут, а на каждом запросе.

Рад, если статья помогла сэкономить кому-то пару часов времени.

BlackCrystalБиблиотека → AJAX-запросы между доменами

Скрипт ВКонтакте MP3

Скрипт стирания выборочных сообщений со стены ВКонтакте

Скрипт удаления из всех групп ВКонтакте

Регенерация Session Id в Symfony - фича или баг?

Скрипт стирания сообщений со стены ВКонтакте

AJAX-запросы между доменами

Найти друзей слова causes. Часть первая.

Удобное размещение папки с проектом Symfony

Подготовка мини-копий картинок (thumbs) на лету

Расширяем возможности sfWebResponse

Отображение ошибок валидации

Проверка персонального кода sfValidatorIsikukood

Правила и соглашение

1999-2009 BlackCrystal ¬|г Clan.    2007-2012 BlackCrystal Ltd.    2011-2012 BlackCrystal Club.