为什么浏览器在AJAX请求返回后没有设置cookie?

Mat*_*man 47 cookies ajax

我正在使用$ .ajax发出ajax请求.响应已设置Set-Cookie标头(我已在Chrome开发工具中对此进行了验证).但是,浏览器在收到响应后没有设置cookie!当我导航到我的域中的另一个页面时,不会发送cookie.(注意:我没有做任何跨域的ajax请求;请求与文档位于同一个域中.)

我错过了什么?

编辑:这是我的ajax请求的代码:

$.post('/user/login', JSON.stringify(data));
Run Code Online (Sandbox Code Playgroud)

以下是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"}:
Run Code Online (Sandbox Code Playgroud)

响应:

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
Run Code Online (Sandbox Code Playgroud)

Mat*_*man 54

好的,所以我终于找到了问题所在.事实证明,Path在AJAX请求中发送cookie时,设置选项很重要.如果你设置Path=/,例如:

Set-Cookie:SessionId=foo; Path=/; HttpOnly
Run Code Online (Sandbox Code Playgroud)

...然后浏览器将在您导航到其他页面时设置cookie.如果没有设置Path,浏览器将使用"默认"路径.显然,AJAX请求设置的cookie的默认路径与直接导航到页面时使用的默认路径不同.我正在使用Go/Martini,所以在服务器端我这样做:

session.Options(session.Options{HttpOnly: true, Path:"/"})
Run Code Online (Sandbox Code Playgroud)

我猜是Python/Ruby /等.有类似的设置机制Path.

另请参阅:PHP和AJAX中的cookie问题


ato*_*irk 36

如果您使用的是新fetchAPI,可以尝试包括credentials:

fetch('/users', {
  credentials: 'same-origin'
})
Run Code Online (Sandbox Code Playgroud)

这就是为我解决的问题.

特别是,使用polyfill:https://github.com/github/fetch#sending-cookies


The*_*Pea 17

@ atomkirk的回答并不适合我,因为

  1. 我不使用fetchAPI
  2. 我正在提出跨站请求(即CORS)

但答案帮助我实现了这些飞跃:

fetchAPI CORS请求需要{credentials:'include'}用于发送和接收的cookie

对于CORS请求,请使用"include"值以允许 凭据发送到其他域:

fetch('https://example.com:1234/users', {   
            credentials: 'include' 
})
Run Code Online (Sandbox Code Playgroud)

...要选择接受来自服务器的cookie,您必须使用凭证选项.


{credentials:'include'} 只是设置 xhr.withCredentials=true

检查fetch代码

if (request.credentials === 'include') {
      xhr.withCredentials = true
 } 
Run Code Online (Sandbox Code Playgroud)

所以简单的Javascript/XHR.withCredentials是重要的部分.


如果您正在使用jQuery,则可以使用" 创建问题"进行设置$.ajaxSetup(...)

$.ajaxSetup({
             crossDomain: true,
             xhrFields: {
                 withCredentials: true
             }
         });
Run Code Online (Sandbox Code Playgroud)

如果您使用的是Angular,则$http服务配置arg接受一个withCredentials属性:

$http({
    withCredentials: true
});
Run Code Online (Sandbox Code Playgroud)

至于要求,何时xhr.withCredentials=true; Cookie标头已发送

在我改变之前 xhr.withCredentials=true

  1. 我可以在响应中看到Set-Cookie名称和值,但是开发人员工具中Chrome的"应用程序"选项卡向我显示了名称和空值
  2. 后续的请求没有发送一个Cookie请求头.

改变之后 xhr.withCredentials=true

  1. 可以在Chrome的"应用程序"标签中看到 cookie的名称和cookie的(与Set-Cookie标头一致的值).
  2. 后续请求确实发送了Cookie具有相同值的请求标头,因此我的服务器将我视为"已验证"

至于响应:服务器可能需要某些Access-Control-*标头

例如,我配置我的服务器以返回这些标头:

  • 访问控制允许的凭据:真
  • 访问控制允许来源:https://开头{你原产} {您的端口}

在我将此服务器端更改为响应标头之前,Chrome在控制台中记录了错误

加载失败https://{saml-domain}/saml-authn:重定向来自https://{saml-domain}/saml-redirectCORS策略已被阻止:

'Access-Control-Allow-Credentials'响应中标头的值是请求的凭据模式时''必须'true'的值'include'.https://{your-domain}因此不允许原点访问.

XMLHttpRequest发起的请求的凭据模式由withCredentials属性控制.

在更改Access-*标头后,Chrome没有记录错误; 浏览器让我检查所有后续请求的经过身份验证的响应.

  • `用于发送和接收 cookie` 这确实有帮助。 (3认同)