为什么浏览器在AJAX请求返回后不设置cookies?

为什么浏览器在AJAX请求返回后不设置cookies?,ajax,cookies,Ajax,Cookies,我正在使用$.ajax发出ajax请求。响应中设置了集Cookie标题集(我已经在Chrome开发工具中验证了这一点)。但是,浏览器在收到响应后不会设置cookie!当我导航到域中的另一个页面时,cookie不会被发送。(注意:我没有执行任何跨域ajax请求;请求与文档位于同一个域中。) 我错过了什么 编辑:以下是我的ajax请求的代码: $.post('/user/login', JSON.stringify(data)); 以下是Chrome开发工具显示的请求: Request URL:h

我正在使用$.ajax发出ajax请求。响应中设置了
集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

好的,我终于解决了问题。事实证明,在AJAX请求中发送cookie时,设置
Path
选项非常重要。如果设置路径=/,例如:

Set-Cookie:SessionId=foo; Path=/; HttpOnly
…然后,当您导航到其他页面时,浏览器将设置cookie。在不设置路径的情况下,浏览器使用“默认”路径。显然,AJAX请求设置的cookie的默认路径与直接导航到页面时使用的默认路径不同。我使用Go/Martini,因此在服务器端我执行以下操作:

session.Options(session.Options{HttpOnly: true, Path:"/"})
我猜Python/Ruby/等也有类似的机制来设置
Path


另请参见:

如果您正在使用新的
获取
API,您可以尝试包括
凭据

fetch('/users', {
  credentials: 'same-origin'
})
这就是我修好它的原因

特别是,使用polyfill:

@atomkirk的不适用于我,因为

  • 我不使用
    fetch
    API
  • 我提出了跨站点请求(即CORS)
  • 注意:如果您的服务器使用
    访问控制允许来源:
    (也称为“所有来源”/“通配符来源”)
    ,则您可能无法发送凭据(见下文)

    至于
    fetch
    API;CORS请求将同时用于发送和接收cookie

    对于CORS请求,使用“包含”值允许发送 其他域的凭据:

    fetch('https://example.com:1234/users', {   
                credentials: 'include' 
    })
    
    。。。要选择从服务器接受cookies,必须使用凭据选项


    {凭证:'include'}
    仅设置

    重要的部分也是如此


    如果您使用的是jQuery,那么您可以使用
    $.ajaxSetup(…)


    如果您使用的是AngularJS,则接受带有凭据的
    属性:


    如果使用角度(角度IO),则接受带有凭据的
    属性:

    this.http.post(this.heroesUrl,hero{
    证书:正确
    });
    

    对于请求,当
    xhr.withCredentials=true时
    ;发送Cookie标头

    在我更改之前
    xhr.withCredentials=true

  • 我可以在响应中看到Set Cookie name&value,但开发者工具中Chrome的“应用程序”选项卡向我显示了名称和一个空值
  • 后续请求未发送
    Cookie
    请求头
  • 更改后
    xhr.withCredentials=true

  • 可以在Chrome的“应用程序”选项卡中看到cookie的名称和cookie的(与设置的cookie标题一致的值)
  • 后续请求发送了具有相同值的
    Cookie
    请求头,因此我的服务器将我视为“已验证”

  • 至于响应:服务器可能需要某些
    访问控制…
    标题

    例如,我将服务器配置为返回以下标题:

    • 访问控制允许凭据:true
    • 访问控制允许源站:https://{您的源站}:{您的端口}
    编辑:如果您允许,这种方法将不起作用(感谢@ChandanBhattad):

    尝试CORS请求时设置了凭据标志,但服务器使用通配符(“*”)作为访问控制允许源的值进行配置,该值不允许使用凭据

    在我对响应头进行服务器端更改之前,Chrome会在控制台中记录错误,如

    未能加载
    https://{saml domain}/saml authn
    :从
    https://{saml domain}/saml重定向的重定向已被CORS策略阻止:

    响应中
    'Access-Control-Allow-Credentials'
    头的值为
    '
    ,当请求的凭据模式为
    'include'
    时,该值必须为
    'true'
    。因此,不允许访问源
    https://{your domain}

    XMLHttpRequest启动的请求的凭据模式由withCredentials属性控制


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

    这可能有助于随机遇到此问题的人


    我发现强制使用https://而不是http://的URL,即使服务器没有证书,Chrome投诉也会解决这个问题

    在我的例子中,cookie大小超过了4096字节(Google Chrome)。我有一个动态cookie负载,它的大小会增加

    如果cookie超过浏览器限制,浏览器将忽略
    设置cookie
    响应头,并且不会设置cookie

    每个浏览器的cookie大小限制


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

    Dayum,这很有用!在java中(使用ServletAPI):
    cookie.setPath(“/”最后!!我们中的两个人花了一天的时间试图弄明白为什么我们的CORS+AJAX cookies不起作用!谢谢,我花了几个小时想弄明白。花了一些时间寻找解决方案
    
    if (request.credentials === 'include') {
          xhr.withCredentials = true
     } 
    
    $.ajaxSetup({
                 crossDomain: true,
                 xhrFields: {
                     withCredentials: true
                 }
             });
    
    $http({
        withCredentials: true
    });
    
    this.http.post<Hero>(this.heroesUrl, hero, {
        withCredentials: true
    });