jQuery getJSON не отправляет куки

Я включаю JS на домен1 форма домен2

<script type="text/javascript" src="http://www.domain2.com/script.js"></script>

этот скрипт не загружается и при нажатии кнопки JSONP-запрос к domain2

$.getJSON( 'http://www.domain2.com/process?callback=?',
    function(data){
        if ( data ) processData( data );
    }
);

и затем отображение данных на домене1.

Итак, вот моя проблема: запрос getJSON не отправляет куки в домен2. Самое странное, что он отправляет печенье полдня, а другая половина - нет.:-)

Вот как выглядит запрос, когда он не работает:

Request details
GET /ajax/embed-user-library?detail=98&callback=jsonp1312398534998 HTTP/1.1 
User-Agent: Opera/9.80 (Windows NT 6.1; U; en) Presto/2.9.168 Version/11.50
Host: www.floowie.com
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: en,sk-SK;q=0.9,sk;q=0.8
Accept-Encoding: gzip, deflate
Referer: http://www.sokker.cz/en/test2
Connection: Keep-Alive

Response details
HTTP/1.1 200 OK 
Date: Wed, 03 Aug 2011 19:06:51 GMT
Server: Apache/2.2.16 (Debian)
X-Powered-By: PHP/5.3.5-0.dotdeb.1
Set-Cookie: SESSID=64292b70dc28d7c6c9f13f70070353d8; path=/; domain=.floowie.com
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Content-Length: 34
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: application/json

И вот когда это работает (в скриптах ничего не изменилось):

Request details
GET /ajax/embed-user-library?detail=99&test=1&callback=jsonp1312398534999 HTTP/1.1 
User-Agent: Opera/9.80 (Windows NT 6.1; U; en) Presto/2.9.168 Version/11.50
Host: test1.floowie.com
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: en,sk-SK;q=0.9,sk;q=0.8
Accept-Encoding: gzip, deflate
Referer: http://www.sokker.cz/en/test2
Cookie: __utma=254918925.1489796832.1301725317.1312260335.1312298033.44; __utmz=254918925.1312298033.44.11.utmcsr=sokker.cz|utmccn=(referral)|utmcmd=referral|utmcct=/en/test2; lang=en; FLWSESSID=ddd1bc696f83f5a70b5f0f3ae30b4691; __utma=121955676.1030804516.1282595153.1312390656.1312397285.194; __utmb=121955676.8.10.1312397285; __utmc=121955676; __utmz=121955676.1312397285.194.21.utmcsr=floowie.crmserver.cz|utmccn=(referral)|utmcmd=referral|utmcct=/index.php
Connection: Keep-Alive

Response details
HTTP/1.1 200 OK 
Date: Wed, 03 Aug 2011 19:07:45 GMT
Server: Apache/2.2.16 (Debian)
X-Powered-By: PHP/5.3.5-0.dotdeb.1
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Content-Length: 20
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: application/json

Кто-то видел такое поведение? Это разрешимо?

Спасибо

3 ответа

Если вы хотите использовать петиции AJAX для разных доменов / поддоменов, вам необходимо реализовать Cross Origin Requests.

Рекомендации:

Примеры:

Ваш сервер должен отправить следующие заголовки:

  • Access-Control-Allow-Origin: test1.floowie.com
  • Access-Control-Allow-Credentials: true // разрешить cookie/ учетные данные сеанса
  • Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS

Вы можете вернуть Access-Control-Allow-Origin глобально или установить его в зависимости от заголовка вашего входного запроса Origin ($ _SERVER ['HTTP_ORIGIN']). Также применимо для Access-Control-Allow-Methods.

Вы должны реализовать петицию ОПЦИИ. Перед первым вызовом AJAX современные браузеры вызывают этот URL с помощью метода OPTIONS, чтобы получить вышеуказанные заголовки.

Хорошо, это первая часть, вторая с jQuery. Прочитайте очень внимательно эту страницу: http://api.jquery.com/jQuery.ajax/

Вам нужно будет добавить некоторые опции к каждому вызову AJAX, вы можете сделать это глобально:

$(document).ajaxSend(function (event, xhr, settings) {
    settings.xhrFields = {
        withCredentials: true
    };
});

Или конкретный:

$.ajax({
    url: a_cross_domain_url,
    xhrFields: {
        withCredentials: true
    }
});

Эта проблема заставила меня потерять много часов... надеюсь, это поможет.

Обратите внимание, что вам не нужно указывать домен cookie как ".floowie.com", если хотите.

Вы должны правильно реализовать запросы CORS с учетными данными для отправки и получения файлов cookie через Ajax. См. Developer.mozilla.org, в частности, в разделе "Запросы с учетными данными".

Прежде всего, вот простой запрос CORS Ajax с учетными данными, используя jQuery 1.5.1+:

$.ajax({
    url: "http://www.domain2.com/process",
    xhrFields: {
        withCredentials: true
    }
}).done(function (data) { console.log(data); });

Обратите внимание withCredentials флаг в полях xhrFields. Этот флаг говорит браузеру отправлять куки с запросом на внешний домен, а не на исходный домен. В вашем случае файлы cookie для www.domain2.com будут отправлены, и вы получите доступ к ним на стороне сервера.

На стороне сервера вам нужно добавить определенные заголовки к ответу:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: www.domain1.com

Важно: запросы с учетными данными не могут установить глобальный заголовок Access-Control-Allow-Origin (Access-Control-Allow-Origin: *). Необходимо указать домены (Access-Control-Allow-Origin: www.domain1.com).

Очевидно, что лучше указать домен для заголовка Access-Control-Allow-Origin. Но если вы не знаете или не знаете, откуда поступил запрос CORS, вы можете использовать Origin заголовок из запроса и просто установите заголовок Access-Control-Allow-Origin вашего ответа на это. В C# вот как мы это сделали:

this.Response.AddHeader("Access-Control-Allow-Origin", this.Request.Headers["Origin"]);

После всего этого куки, которые вы установили на стороне сервера, будут отправлены обратно с ответом, и браузер сможет правильно обработать их и вставить в хранилище куки браузера для www.domain2.com. И любые последующие запросы CORS, которые вы отправляете, будут также отправлять эти куки в запросе.

Если вы отправляете запрос, отличный от методов GET, POST или HEAD, вам нужно будет выполнить Предварительно просвеченные запросы (см. Раздел "Предварительно просвеченные запросы"):

В отличие от простых запросов (обсужденных выше), "предварительно выданные" запросы сначала отправляют HTTP-запрос методом OPTIONS ресурсу в другом домене, чтобы определить, безопасен ли фактический запрос для отправки. Межсайтовые запросы предварительно просматриваются следующим образом, так как они могут иметь значение для пользовательских данных. В частности, запрос предварительно просвечивается, если:

  • Он использует методы, отличные от GET, HEAD или POST. Кроме того, если POST используется для отправки данных запроса с Content-Type, отличным от application/x-www-form-urlencoded, multipart/form-data или text/plain, например, если запрос POST отправляет полезную нагрузку XML на сервер используя application/xml или text/xml, запрос предварительно просвечивается.

  • Он устанавливает пользовательские заголовки в запросе (например, запрос использует заголовок, такой как X-PINGOTHER)

Дополнительная информация о IE8 и IE9: приведенный выше вызов Ajax завершится неудачно в IE8 и 9. Я включил файл JS из https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest на мою страницу, и это автоматически позволило CORS-запросам работать в этих старых версиях IE. Но, к сожалению, объект XDomainRequest, созданный MS для IE8 и 9, не позволяет отправлять или получать файлы cookie. (см. это сообщение в блоге MSDN для получения дополнительной информации)

У вас разные хозяева. В первом примере хостом является "Host: www.floowie.com". Во втором это "Host: test1.floowie.com".

Я предполагаю, что файлы cookie изначально установлены на "test1.floowie.com", а вы не указали, что они должны быть доступны для ".floowie.com" (т. Е. Весь домен и все субдомены).

Можете ли вы опубликовать код, который устанавливает куки в первую очередь?

Если вы исправите это, оно должно по крайней мере показать последовательное поведение. Тем не менее, IE, вероятно, все еще не будет передавать куки через поддоменов. Это то, с чем я борюсь в данный момент, как я могу ответить на ваш вопрос.

Другие вопросы по тегам