Почему браузер не устанавливает файлы cookie после возвращения запроса AJAX?
Я делаю запрос ajax, используя $.ajax. Ответ имеет набор заголовков Set-Cookie
(я проверял это в инструментах Chrome dev). Однако браузер не устанавливает cookie после получения ответа! Когда я перехожу на другую страницу в своем домене, cookie не отправляется. (Примечание: я не выполняю межсайтовые запросы ajax, запрос находится в том же домене, что и документ.)
Что мне не хватает?
EDIT: Вот код для моего запроса ajax:
$.post('/user/login', JSON.stringify(data));
Вот запрос, как показано в инструментах Chrome dev:
Request URL:https://192.168.1.154:3000/user/login
Request Method:POST
Status Code:200 OK
Request Headers:
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:35
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
DNT:1
Host:192.168.1.154:3000
Origin:https://192.168.1.154:3000
Referer:https://192.168.1.154:3000/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36
X-Requested-With:XMLHttpRequest
Form Data:
{"UserId":"blah","Password":"blah"}:
Ответ:
Response Headers:
Content-Length:15
Content-Type:application/json; charset=UTF-8
Date:Sun, 16 Mar 2014 03:25:24 GMT
Set-Cookie:SessionId=MTM5NDk0MDMyNHxEdi1CQkFFQ180SUFBUkFCRUFBQVRfLUNBQUVHYzNSeWFXNW5EQXNBQ1ZObGMzTnBiMjVKWkFaemRISnBibWNNTGdBc1ZFcDNlU3RKVFdKSGIzQlNXRkkwVjJGNFJ6TlRVSHA0U0ZJd01XRktjMDF1Y1c1b2FGWXJORzV4V1QwPXwWf1tz-2Fy_Y4I6fypCzkMJyYxhgM3LjVHGAlKyrilRg==; HttpOnly
Ответы
Ответ 1
ОК, поэтому я, наконец, понял проблему. Оказывается, установка параметра Path
важна при отправке файлов cookie в запросе AJAX. Если вы установили Path=/
, например:
Set-Cookie:SessionId=foo; Path=/; HttpOnly
... тогда браузер будет устанавливать cookie при переходе на другую страницу. Без настройки Path
браузер использует путь по умолчанию. По-видимому, путь по умолчанию для cookie, заданный по запросу AJAX, отличается от пути по умолчанию, используемого при непосредственном перемещении по странице. Я использую Go/Martini, поэтому на стороне сервера я делаю это:
session.Options(session.Options{HttpOnly: true, Path:"/"})
Я бы предположил, что Python/Ruby/etc. имеют аналогичный механизм для установки Path
.
См. также: проблема с cookie в PHP и AJAX
Ответ 2
Если вы используете новый API fetch
, вы можете попробовать включить credentials
:
fetch('/users', {
credentials: 'same-origin'
})
То, что исправило это для меня.
В частности, используя polyfill: https://github.com/github/fetch#sending-cookies
Ответ 3
@atomkirk ответ не совсем применим ко мне, потому что
- Я не использую API
fetch
- Я делал межсайтовые запросы (т.е. CORS)
Но ответ помог мне совершить эти прыжки:
fetch
Запросы API CORS требуется {credentials:'include'}
для отправки и получения файлов cookie
Для запросов CORS используйте значение "включить", чтобы разрешить отправкуучетные данные для других доменов:
fetch('https://example.com:1234/users', {
credentials: 'include'
})
... Чтобы выбрать принятие файлов cookie с сервера, вы должны использовать параметр учетных данных.
{credentials:'include'}
просто устанавливает xhr.withCredentials=true
Проверить fetch
код
if (request.credentials === 'include') {
xhr.withCredentials = true
}
Так что обычный Javascript/XHR.withCredentials является важной частью.
Если вы используете jQuery, вы можете установить withCredentials с помощью $.ajaxSetup(...)
$.ajaxSetup({
crossDomain: true,
xhrFields: {
withCredentials: true
}
});
Что касается запроса, когда xhr.withCredentials=true
; заголовок Cookie отправляется
Прежде чем я изменил xhr.withCredentials=true
- Я мог видеть имя и значение Set-Cookie в ответе, но вкладка "Приложение" Chrome в Инструментах разработчика показала мне имя и пустое значение
- Последующие запросы не отправили a
Cookie
заголовок запроса.
После изменения xhr.withCredentials=true
- Я мог видеть имя файла cookie и значение файла cookie на вкладке "Приложение" Chrome (значение, соответствующее Set-Cookie заголовок).
- Последующие запросы сделали отправили заголовок запроса
Cookie
с тем же значением, поэтому мой сервер обработал меня как "аутентифицированный"
Что касается ответа: серверу могут понадобиться определенные заголовки Access-Control- *
Например, я настроил сервер для возврата этих заголовков:
- Access-Control-Allow-Credentials: истинная
- Access-Control-Allow-Origin: https://{ваши-происхождения}: {вашего порт}
Пока я не сделал это изменение на стороне сервера в заголовках ответов, Chrome зарегистрировал ошибки в консоли, например
Не удалось загрузить https://{saml-domain}/saml-authn
: перенаправление с https://{saml-domain}/saml-redirect
было заблокировано политикой CORS:
Значение заголовка 'Access-Control-Allow-Credentials'
в ответе ''
, которое должно быть 'true'
, когда режим учетных данных запроса 'include'
. Происхождение https://{your-domain}
, следовательно, не допускается.
Режим учетных данных запросов, инициированных XMLHttpRequest, контролируется атрибутом withCredentials.
После внесения этого изменения заголовка Access- *, Chrome не регистрировал ошибки; браузер позволяет проверить аутентифицированные ответы для всех последующих запросов.