为什么浏览器在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 10:24:37  来源:igfitidea点击:

Why is the browser not setting cookies after an AJAX request returns?

ajaxcookies

提问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

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

回答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 的回答并不完全适用于我,因为

  1. I don't use the fetchAPI
  2. I was making cross-siterequests (i.e. CORS)
  1. 我不使用fetchAPI
  2. 我正在发出跨站点请求(即 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

Check fetchcode

校验fetch

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

  1. 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
  2. Subsequent requests did not senda Cookierequest header.
  1. 我可以在响应中看到 Set-Cookie 名称和值,但是开发者工具中 Chrome 的“应用程序”选项卡向我显示了名称和一个空值
  2. 后续的请求没有发送一个Cookie请求头。

After the change xhr.withCredentials=true

更改后 xhr.withCredentials=true

  1. I could seethe cookie's nameand the cookie's valuein the Chrome's "Application" tab (a value consistent with the Set-Cookie header).
  2. Subsequent requests didsend a Cookierequest header with the same value, so my server treated me as "authenticated"
  1. 可以在 Chrome 的“应用程序”选项卡(与 Set-Cookie 标头一致的值)看到cookie 的名称和 cookie 的
  2. 后续请求确实发送了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 from https://{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'. Origin https://{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 :)

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