为啥 AJAX 请求返回后浏览器不设置 cookie?
Posted
技术标签:
【中文标题】为啥 AJAX 请求返回后浏览器不设置 cookie?【英文标题】:Why is the browser not setting cookies after an AJAX request returns?为什么 AJAX 请求返回后浏览器不设置 cookie? 【发布时间】:2014-04-21 08:59:09 【问题描述】:我正在使用 $.ajax 发出 ajax 请求。响应具有 Set-Cookie
标头集(我已经在 Chrome 开发工具中验证了这一点)。但是,浏览器在收到响应后不设置cookie!当我导航到我域中的另一个页面时,不会发送 cookie。 (注意:我没有做任何跨域 ajax 请求;请求与文档在同一个域中。)
我错过了什么?
编辑:这是我的 ajax 请求的代码:
$.post('/user/login', JSON.stringify(data));
这是请求,如 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 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
【问题讨论】:
所以这可能是一个旧线程,但我偶然发现它正在寻找其他东西,我注意到您的请求在标题中有DNT: 1
。如果我记得,这是 Do Not Track,浏览器要求不允许设置 cookie。
如果您在使用 Apollo 时遇到此问题,请查看他们的文档中的 this section
【参考方案1】:
@atomkirk 的 answer 不适用于我,因为
-
我不使用
fetch
API
我正在发出跨站点请求(即 CORS)
注意:如果您的服务器使用Access-Control-Allow-Origins:*
(又名“所有来源”/“通配符来源”),您可能无法发送凭据(请参阅下面)。
至于fetch
API; CORS 请求将 need credentials:'include'
用于发送和接收 cookie
对于 CORS 请求,使用“include”值来允许发送 其他域的凭据:
fetch('https://example.com:1234/users', credentials: 'include' )
...要选择接受来自服务器的 cookie,您必须使用凭据选项。
credentials:'include'
只是设置xhr.withCredentials=true
Check fetch
code
if (request.credentials === 'include') xhr.withCredentials = true
所以plain javascript/XHR.withCredentials是重要的部分。
如果你使用 jQuery,你 can set withCredentials(记得使用 crossDomain: true
)使用 $.ajaxSetup(...)
$.ajaxSetup( crossDomain: true, xhrFields: withCredentials: true );
如果您使用的是 AngularJS,$http
service config arg 接受 withCredentials
属性:
$http( withCredentials: true );
如果您使用 Angular (Angular IO),common.http.HttpRequest
service options arg 接受 withCredentials
属性:
this.http.post<Hero>(this.heroesUrl, hero, withCredentials: true );
至于请求,当xhr.withCredentials=true
;发送 Cookie 标头
在我改变之前xhr.withCredentials=true
-
我可以在响应中看到 Set-Cookie 名称和值,但开发者工具中 Chrome 的“应用程序”选项卡向我显示了名称和 空值
后续请求未发送
Cookie
请求标头。
更改后xhr.withCredentials=true
-
我可以在 Chrome 的“应用程序”选项卡中看到 cookie 的 名称 和 cookie 的 值(与 Set-Cookie 一致的值标题)。
后续请求确实发送了具有相同值的
Cookie
请求标头,因此我的服务器将我视为“已验证”
至于响应:服务器可能需要某些Access-Control...
标头
例如,我将服务器配置为返回这些标头:
访问控制允许凭据:true Access-Control-Allow-Origin:https://your-origin:your-port编辑:如果您允许all origins/wildcard origins, as described here(感谢@ChandanBhattad),此方法将不起作用:
尝试使用设置了凭据标志的 CORS 请求,但服务器使用通配符 ("*") 作为 Access-Control-Allow-Origin 的值进行配置,这不允许使用凭据。
在我对响应标头进行此服务器端更改之前,Chrome 会在控制台中记录错误,例如
无法加载
https://saml-domain/saml-authn
:从https://saml-domain/saml-redirect
重定向已被 CORS 策略阻止:
响应中
'Access-Control-Allow-Credentials'
标头的值为''
,当请求的凭据模式为'include'
时,必须为'true'
。 Originhttps://your-domain
因此不允许访问。
XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制。
在进行此 Access-* 标头更改后,Chrome 没有记录错误;浏览器让我检查所有后续请求的经过身份验证的响应。
【讨论】:
for both sending & RECEIVING cookies
确实有帮助。
这似乎是正确的答案。在 ajax POST 请求中处理了用户身份验证,但未设置 cookie。有趣的是,这个问题只发生在移动浏览器上,而不是桌面浏览器上。 xhrFields: withCredentials: true 参数显然解决了这个问题。太糟糕了,我在解决问题后找到了这个答案,这让我发疯了几天。
发送和接收.. 真实的。我正在使用 withCredentials: false 设置 POST 到我的登录端点,并花了 4 个多小时试图弄清楚为什么我们没有设置 cookie。
谢谢。我和你的情况一样,使用跨站点cookies(我的后端在一个主机上运行,前端在另一个主机上运行)。除了我没有在登录请求中使用 withCredentials 标志外,我已经准备好了一切,只在后续请求中使用。一旦我在登录请求中使用它(必须以正确的方式配置我的 CORS 策略,因为它不喜欢允许的来源是 *),它工作正常。
谢谢。如果我设置了 "access-control-allow-origin:*" ,这似乎不起作用。基本上 - “凭据”:当 access-control-allow-origin 设置为 * 时不允许“包含”?【参考方案2】:
在我的例子中,cookie 大小超过了 4096 字节(谷歌浏览器)。我有一个会增加大小的动态 cookie 有效负载。
如果 cookie 超出浏览器限制,浏览器将忽略 set-cookie
响应头,并且不会设置 cookie。
See here 用于每个浏览器的 cookie 大小限制。
我知道这不是解决方案,但这是我的问题,我希望它可以帮助某人:)
【讨论】:
【参考方案3】:这可能会帮助某人随机遇到这个问题。
我发现强制使用 https:// 而不是 http:// 的 URL,即使服务器没有证书并且 Chrome 抱怨会解决这个问题。
【讨论】:
【参考方案4】:好的,所以我终于找到了问题所在。事实证明,在 AJAX 请求中发送 cookie 时,设置 Path
选项很重要。如果设置Path=/
,例如:
Set-Cookie:SessionId=foo; Path=/; HttpOnly
...那么当您导航到不同的页面时,浏览器将设置 cookie。不设置Path
,浏览器使用“默认”路径。显然,AJAX 请求设置的 cookie 的默认路径与直接导航到页面时使用的默认路径不同。我正在使用 Go/Martini,所以在服务器端我这样做:
session.Options(session.OptionsHttpOnly: true, Path:"/")
我猜是 Python/Ruby/等。有类似的机制来设置Path
。
另请参阅:cookies problem in php and AJAX
【讨论】:
Dayum,这很有用!在 java 中(使用 servlet API):cookie.setPath("/");
终于!!我们两个人花了一天时间试图弄清楚为什么我们的 CORS+AJAX cookie 不起作用!
谢谢,我花了几个小时试图解决这个问题。
花了一些时间寻找解决方案并将路径添加到 cookie 中【参考方案5】:
如果您使用新的fetch
API,可以尝试包含credentials
:
fetch('/users',
credentials: 'same-origin'
)
这就是为我解决的问题。
特别是使用 polyfill:https://github.com/github/fetch#sending-cookies
【讨论】:
我和@jag 在这个!!我只花了 4 个小时尝试使用 passport.js 通过 ajax 登录......直到我点击返回 cookie 的网络响应,这完全是个谜。它根本不会保存。您的解决方案修复了它。干杯 在 set-cookie 响应中添加凭据和路径后,它适用于我 注意:如果您的 api 位于另一个域中,则需要使用credentials: 'include'
。此外,如果您在使用 apollo 时遇到此问题,请查看他们的文档中的 this section。以上是关于为啥 AJAX 请求返回后浏览器不设置 cookie?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 jQuery 的 .ajax() 方法不发送我的会话 cookie?
仅仅通过Ajax(XMLHttpRequest)请求,能否将cookie保存到游览器上?