为什么浏览器在 AJAX 请求返回后不设置 cookie?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22432616/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is the browser not setting cookies after an AJAX request returns?
提问by Matt Fichman
I am making an ajax request using $.ajax. The response has the Set-Cookieheader set (I've verified this in the Chrome dev tools). However, the browser does notset the cookie after receiving the response! When I navigate to another page within my domain, the cookie is not sent. (Note: I'm not doing any cross-domain ajax requests; the request is in the same domain as the document.)
我正在使用 $.ajax 发出 ajax 请求。响应Set-Cookie设置了标头(我已经在 Chrome 开发工具中验证了这一点)。但是浏览器在收到响应后并没有设置cookie!当我导航到我域中的另一个页面时,不会发送 cookie。(注意:我没有做任何跨域 ajax 请求;请求与文档在同一个域中。)
What am I missing?
我错过了什么?
EDIT: Here is the code for my ajax request:
编辑:这是我的 ajax 请求的代码:
$.post('/user/login', JSON.stringify(data));
Here is the request, as shown by the Chrome dev tools:
这是请求,如 Chrome 开发工具所示:
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:
回复:
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
回答by Matt Fichman
OK, so I finally figured out the problem. It turns out that setting the Pathoption is important when sending cookies in an AJAX request. If you set Path=/, e.g.:
好的,所以我终于找到了问题所在。事实证明,Path在 AJAX 请求中发送 cookie 时设置该选项很重要。如果你设置Path=/,例如:
Set-Cookie:SessionId=foo; Path=/; HttpOnly
...then the browser will set the cookie when you navigate to a different page. Without setting Path, the browser uses the "default" path. Apparently, the default path for a cookie set by an AJAX request is different from the default path used when you navigate to a page directly. I'm using Go/Martini, so on the server-side I do this:
...然后浏览器将在您导航到不同页面时设置 cookie。没有设置Path,浏览器使用“默认”路径。显然,AJAX 请求设置的 cookie 的默认路径与直接导航到页面时使用的默认路径不同。我正在使用 Go/Martini,所以在服务器端我这样做:
session.Options(session.Options{HttpOnly: true, Path:"/"})
I'd guess that Python/Ruby/etc. have a similar mechanism for setting Path.
我猜想 Python/Ruby/etc. 有类似的设置机制Path。
See also: cookies problem in PHP and AJAX
回答by atomkirk
If you're using the new fetchAPI, you can try including credentials:
如果您使用的是新fetchAPI,则可以尝试包括credentials:
fetch('/users', {
credentials: 'same-origin'
})
That's what fixed it for me.
这就是为我修复它的原因。
In particular, using the polyfill: https://github.com/github/fetch#sending-cookies
特别是,使用 polyfill:https: //github.com/github/fetch#sending-cookies
回答by The Red Pea
@atomkirk's answerdidn't quite apply to me because
@atomkirk 的回答并不完全适用于我,因为
- I don't use the
fetchAPI - I was making cross-siterequests (i.e. CORS)
- 我不使用
fetchAPI - 我正在发出跨站点请求(即 CORS)
But the answer helped me make these leaps:
但答案帮助我实现了这些飞跃:
fetchAPI CORS requests needs {credentials:'include'}for both sending & receiving cookies
fetch发送和接收 cookie 的API CORS 请求需要{credentials:'include'}
For CORS requests, use the "include" value to allow sendingcredentials to other domains:
fetch('https://example.com:1234/users', { credentials: 'include' })... To opt into acceptingcookies from the server, you must use the credentials option.
对于 CORS 请求,使用“include”值允许向其他域发送凭据:
fetch('https://example.com:1234/users', { credentials: 'include' })... 要选择接受来自服务器的 cookie,您必须使用凭据选项。
{credentials:'include'}just sets xhr.withCredentials=true
{credentials:'include'}只是设置 xhr.withCredentials=true
if (request.credentials === 'include') { xhr.withCredentials = true }
if (request.credentials === 'include') { xhr.withCredentials = true }
So plain Javascript/XHR.withCredentialsis the important part.
所以简单的 Javascript/XHR.withCredentials是重要的部分。
If you're using jQuery, you can set withCredentialsusing $.ajaxSetup(...)
如果您使用的是 jQuery,则可以使用设置 withCredentials$.ajaxSetup(...)
$.ajaxSetup({ crossDomain: true, xhrFields: { withCredentials: true } });
$.ajaxSetup({ crossDomain: true, xhrFields: { withCredentials: true } });
If you're using AngularJS, the $httpservice config argaccepts a withCredentialsproperty:
如果您使用的是 AngularJS,则$http服务配置参数接受一个withCredentials属性:
$http({ withCredentials: true });
$http({ withCredentials: true });
If you're using Angular (Angular IO), the [common.http.HttpRequestservice options arg](
https://angular.io/api/common/http/HttpRequest#withCredentials) accepts a withCredentialsproperty:
如果您使用的是 Angular (Angular IO),则 [ common.http.HttpRequestservice options arg](
https://angular.io/api/common/http/HttpRequest#withCredentials) 接受一个withCredentials属性:
this.http.post<Hero>(this.heroesUrl, hero, { withCredentials: true });
this.http.post<Hero>(this.heroesUrl, hero, { withCredentials: true });
As for the request, when xhr.withCredentials=true; the Cookie header is sent
至于请求,当xhr.withCredentials=true;发送 Cookie 标头
Before I changed xhr.withCredentials=true
在我改变之前 xhr.withCredentials=true
- I could see Set-Cookie name & value in the response, but Chrome's "Application" tab in the Developer Tools showed me the name and an empty value
- Subsequent requests did not senda
Cookierequest header.
- 我可以在响应中看到 Set-Cookie 名称和值,但是开发者工具中 Chrome 的“应用程序”选项卡向我显示了名称和一个空值
- 后续的请求没有发送一个
Cookie请求头。
After the change xhr.withCredentials=true
更改后 xhr.withCredentials=true
- I could seethe cookie's nameand the cookie's valuein the Chrome's "Application" tab (a value consistent with the Set-Cookie header).
- Subsequent requests didsend a
Cookierequest header with the same value, so my server treated me as "authenticated"
- 我可以在 Chrome 的“应用程序”选项卡(与 Set-Cookie 标头一致的值)中看到cookie 的名称和 cookie 的值。
- 后续请求确实发送了
Cookie具有相同值的请求标头,因此我的服务器将我视为“已验证”
As for the response: the server may need certain Access-Control-* headers
至于响应:服务器可能需要某些 Access-Control-* 标头
For example, I configured my server to return these headers:
例如,我将服务器配置为返回这些标头:
- Access-Control-Allow-Credentials:true
- Access-Control-Allow-Origin:https://{your-origin}:{your-port}
- Access-Control-Allow-Credentials:true
- Access-Control-Allow-Origin:https://{your-origin}:{your-port}
Until I made this server-side change to the response headers, Chrome logged errors in the console like
在我对响应标头进行服务器端更改之前,Chrome 在控制台中记录了错误,例如
Failed to load
https://{saml-domain}/saml-authn: Redirect fromhttps://{saml-domain}/saml-redirecthas been blocked by CORS policy:The value of the
'Access-Control-Allow-Credentials'header in the response is''which must be'true'when the request's credentials mode is'include'. Originhttps://{your-domain}is therefore not allowed access.The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
加载失败
https://{saml-domain}/saml-authn:重定向https://{saml-domain}/saml-redirect自已被 CORS 策略阻止:
'Access-Control-Allow-Credentials'响应中标头的值''必须是'true'当请求的凭据模式为 时'include'。https://{your-domain}因此不允许访问Origin 。XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制。
After making this Access-* header change, Chrome did not log errors; the browser let me check the authenticated responses for all subsequent requests.
更改此 Access-* 标头后,Chrome 没有记录错误;浏览器让我检查所有后续请求的经过身份验证的响应。
回答by CResults
This may help somebody randomly falling across this question.
这可能会帮助某人随机遇到这个问题。
I found forcing a URL with https:// rather than http:// even though the server hasn't got a certificate and Chrome complains will fix this issue.
我发现强制使用 https:// 而不是 http:// 的 URL,即使服务器没有获得证书并且 Chrome 抱怨会解决这个问题。
回答by Nick Hall
In my case, the cookie size exceeded 4096 bytes (Google Chrome). I had a dynamic cookie payload that would increase in size.
就我而言,cookie 大小超过 4096 字节(谷歌浏览器)。我有一个会增加大小的动态 cookie 负载。
Browsers will ignore the set-cookieresponse header if the cookie exceeds the browsers limit, and it will not set the cookie.
set-cookie如果 cookie 超过浏览器限制,浏览器将忽略响应头,并且不会设置 cookie。
See herefor cookie size limits per browser.
请参阅此处了解每个浏览器的 cookie 大小限制。
I know this isn't the solution, but this was my issue, and I hope it helps someone :)
我知道这不是解决方案,但这是我的问题,我希望它可以帮助某人:)

