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.
Рекомендации:
- http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/
- https://developer.mozilla.org/en/http_access_control
Примеры:
Ваш сервер должен отправить следующие заголовки:
- 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, вероятно, все еще не будет передавать куки через поддоменов. Это то, с чем я борюсь в данный момент, как я могу ответить на ваш вопрос.