Калининград+7.962.2626.555

Кроссдоменный AJAX запрос: раз и навсегда про клиентскую и серверную часть

04.10.2016

Каждый раз, как в первый раз с этим кроссдоменным AJAX.

1. JSONP

Клиентская часть выглядит так:

$.ajax({
    type: 'GET', // jsonp всегда будет отправляться GET'ом, даже если принудительно указать POST
    url: 'http://...',
    data: ({
        'var1':value1,
        'var2':value2
    }),
    dataType: 'jsonp',
    jsonp: 'mycallbackfunction',
    crossDomain: true,
    cache: false,
    complete: function(xhr, status) {},
    error: function(xhr, status, message) {},
    success: function(data, status, xhr) {}
});

Жирным выделено самое главное в этом jQuery AJAX запросе:

  • dataType: 'jsonp' — говорим, что хотим получить ответ в jsonp-формате;
  • jsonp: 'mycallbackfunction' — говорим, что функция обратного вызова будет называться mycallbackfunction;
  • crossDomain: true — говорим, что запрос является кроссдоменным.

А теперь серверная часть:

echo $_GET['mycallbackfunction'].'('.json_encode($arrayData).')';

Тут обратите внимание на GET параметр mycallbackfunction — он тут главный.

Обратите внимание, что в этом случае мы никакие специальные заголовки не отдаем.

2. Заголовки

В этом случае мы можем позволить себе простейший запрос:

$.ajax({
    type: 'POST', // В отличие от jsonp, тут можно использовать и POST, и все остальное
    url: 'http://...',
    data: ({
        'var1':value1,
        'var2':value2
    }),
    dataType: 'json',
    crossDomain: false,
    cache: false,
    complete: function(xhr, status) {},
    error: function(xhr, status, message) {},
    success: function(data, status, xhr) {}
});

Обратите внимание, что здесь мы даже не говорим, что запрос кроссдоменный (crossDomain: false) и ждем от сервера вполне понятный JSON, а не «диковенный» JSONP.

Конечно, браузеры нас завернут за такой запрос аргументируя, что отсутствует заголовок CORS «Access-Control-Allow-Origin».

Чтобы все отработало как нужно, добавим в скрипт следующие заголовки:

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Origin,Content-Type,Accept,X-Requested-With');

В первой строке вместо * лучше указать конкретный домен — так будет безопаснее.

Во второй строке работать будет и только с X-Requested-With, а Origin, Content-Type, Accept были подсмотрены в одном из запросов одного из сервисов Яндекса.