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

时间:2014-03-16 03:31:20

标签: ajax cookies

我正在使用$ .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

5 个答案:

答案 0 :(得分:51)

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

Set-Cookie:SessionId=foo; Path=/; HttpOnly

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

session.Options(session.Options{HttpOnly: true, Path:"/"})

我猜想Python / Ruby /等等。有类似的机制来设置Path

另请参阅:cookies problem in PHP and AJAX

答案 1 :(得分:34)

如果您使用新的fetch API,可以尝试添加credentials

fetch('/users', {
  credentials: 'same-origin'
})

这就是为我解决的问题。

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

答案 2 :(得分:14)

@ atomkirk的answer并不适用于我,因为

  1. 我不使用fetch API
  2. 我正在制作跨网站请求(即CORS)
  3. 但答案帮助我实现了这些飞跃:

    fetch API CORS请求needs {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使用$.ajaxSetup(...)

    $.ajaxSetup({
                 crossDomain: true,
                 xhrFields: {
                     withCredentials: true
                 }
             });
    

    如果您使用的是Angular,$http service config arg会接受withCredentials属性:

    $http({
        withCredentials: true
    });
    

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

    在我更改xhr.withCredentials=true

    之前
    1. 我可以看到Set-Cookie name&响应中的值,但Chrome在开发人员工具中的“应用”标签显示了我的名称和空值
    2. 后续请求未发送 Cookie请求标头。
    3. 更改后xhr.withCredentials=true

      1. 可以在Chrome的“应用程序”标签中看到 Cookie的名称以及Cookie的(与Set-Cookie一致的值)头)。
      2. 后续请求 发送具有相同值的Cookie请求标头,因此我的服务器将我视为“已验证”
      3. 至于响应:服务器可能需要某些Access-Control- *标题

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

        • 接入控制允许凭证:真
        • 访问控制允许来源: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未记录错误;浏览器让我检查所有后续请求的经过身份验证的响应。

答案 3 :(得分:1)

这可以帮助某人随机遇到这个问题。

我发现即使服务器没有证书,并且使用https://而不是http://来强制使用URL,Chrome仍抱怨会解决此问题。

答案 4 :(得分:0)

就我而言,Cookie大小超过4096字节(谷歌浏览器)。我有一个动态Cookie有效负载,该负载会增加大小。

如果Cookie超出浏览器限制,浏览器将忽略set-cookie响应标头,并且不会设置Cookie。

See here了解每个浏览器的Cookie大小限制。

我知道这不是解决方案,但这是我的问题,我希望它可以帮助某人:)