Chrome 浏览器如何决定何时发送 OPTIONS?

Posted

技术标签:

【中文标题】Chrome 浏览器如何决定何时发送 OPTIONS?【英文标题】:How does the Chrome browser decide when to send OPTIONS? 【发布时间】:2015-03-10 23:58:02 【问题描述】:

我有一个 AngularJS WebAPI 应用程序。

据我所知,OPTIONS 请求是由浏览器自动构建的。

POST http://localhost:3048/Token HTTP/1.1
Host: localhost:3048
Connection: keep-alive
Content-Length: 78
Accept: application/json, text/plain, */*
Origin: http://localhost:2757
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://localhost:2757/Auth/login
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8

grant_type=password&username=xxx%40live.com&password=xxx

回复:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 971
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.0
Access-Control-Allow-Origin: *
Set-Cookie: .AspNet.Cookies=CpvxrR1gPFNs0vP8GAmcUt0EiKuEzLS1stLl-70O93wsipJkLUZuNdwC8tZc5M0o1ifoCjvnRXKjEBk3nLRbFlbldJLydW2BWonr5JmBjRjXZyKtcc29ggAVhZlc2E-3gGDlyoZLAa5Et8zrAokl8vsSoXmHnsjrxZw0VecB_Ry98Ln84UuKdeHlwSBnfaKKJfsN-u3Rsm6MoEfBO5aAFEekhVBWytrYDx5ks-iVok3TjJgaPc5ex53kp7qrtH3izbjT7HtnrsYYtcfPtmsxbCXBkX4ssCBthIl-NsN2wObyoEqHMpFEf1E9sB86PJhTCySEJoeUJ5u3juTnPlQnHsk1UTcO0tDb39g-_BD-I4FWS5GMwxLNtmut3Ynjir0GndwqsvpEsLls1Y4Pq7UuVCTn7DMO4seb64Sy8oEYkKZYk9tU4tsJuGD2CAIhdSc-lAmTAA78J5NOx23klkiuSe_SSiiZo5uRpas_1CFHjhi1c8ItEMpgeTsvgTkxafq5EOIWKPRxEHbCE8Dv106k5GlKK5BaH6z7ESg5BHPBvY8; path=/; HttpOnly
X-SourceFiles: =?UTF-8?B?QzpcR1xhYmlsaXRlc3Qtc2VydmVyXFdlYlJvbGVcVG9rZW4=?=
X-Powered-By: ASP.NET
Date: Tue, 13 Jan 2015 04:54:55 GMT

"access_token":"TkJ2trqT ....

现在登录

我登出无非就是删除令牌并重新登录。发生了一些不同的事情。之前它没有发送选项,但现在它发送了。之前的请求/响应是否会影响浏览器在我第二次登录时的行为有所不同?

OPTIONS http://localhost:3048/Token HTTP/1.1
Host: localhost:3048
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:2757
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Access-Control-Request-Headers: accept, authorization, content-type
Accept: */*
Referer: http://localhost:2757/Auth/login
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

回复:

HTTP/1.1 400 Bad Request
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 34
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?QzpcR1xhYmlsaXRlc3Qtc2VydmVyXFdlYlJvbGVcVG9rZW4=?=
X-Powered-By: ASP.NET
Date: Tue, 13 Jan 2015 04:56:32 GMT

"error":"unsupported_grant_type"

如果我重置浏览器并重新加载页面,那么它会回到第一次不发送 OPTIONS 之前的状态,我可以登录。

可能我需要更改服务器上的某些内容以便它处理选项。

但是为什么我的浏览器(Chrome)第一次没有发送 OPTIONS?

【问题讨论】:

是AJAX还是有跨域请求? 我不会担心的。它正在发送选项,因为您为 Angular 应用程序使用不同的端口到 api 3048 和 2757。由于 Cors,正在发送选项。 但是只有第二个请求发送选项。这是为什么呢? @Wayne - 是的,它是一个跨域请求。但我很困惑。为什么它第一次不发送任何选项,然后随后的调用它发送一个选项。我的代码和电话是一样的。我正在尝试使登录代码正常工作,并想知道为什么它第一次工作但第二次不工作。我意识到我必须解决为什么它不是第二次但为什么与浏览器不同的行为? @Dilip - 是的,这就是我感到困惑的地方。第一次不发送 OPTIONS。 【参考方案1】:

Chrome(或任何其他浏览器)是否发送 OPTIONS 请求完全由 CORS specfication 指定:

当cross-origin request算法被调用时,必须遵循以下步骤: ... 2.如果满足以下条件,则遵循simple cross-origin request算法:

request method 是 simple method,force preflight flag 未设置。

每个author request headers 都是simple header 或author request headers 为空。

3。否则,请遵循cross-origin request with preflight 算法。注意:使用simple 和author request headers 的方法的跨域请求不是simple 将有一个preflight request 以确保资源可以处理这些标头。 (类似于使用不是simple method 的方法的请求。)

您的 OPTIONS 请求包含以下请求标头:

Access-Control-Request-Headers: accept, <b>authorization</b>, content-type

这意味着您的 Angular 应用程序插入了非simple Authorization 请求标头,可能作为身份验证方案的一部分。非简单的“作者请求标头”会触发 OPTIONS 请求,如您在上面的引用中所见。

要让请求成功,您的服务器应该处理 OPTIONS 请求并响应:

Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Headers: authorization

要了解有关 CORS 的更多信息,请参阅 https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS。

【讨论】:

那些author-request-headers 链接没有显示任何相关信息-我在链接的文档中根本找不到该术语-我认为CORS已从w3c规范中移出。我仍然可以在w3.org/TR/2020/SPSD-cors-20200602/#author-request-headers 找到我认为是您所指的文档【参考方案2】:

当您第一次登录时,您很可能在登录过程中的某处设置了Authorization HTTP 标头。另一方面,您忘记在用户注销时删除此标头。

当您再次尝试登录时,Authorization HTTP 标头仍然存在。这会触发浏览器执行预检请求(参见 Rob W 的解释:https://***.com/a/27924344/548020。考虑到您尝试使用授权类型密码登录,发送Authorization 标头没有意义,因为这意味着您是已经授权(= 登录)。您基本上是在要求您的后端让您登录,同时告诉您的后端您已​​经获得授权(= 登录)。

这可以通过简单的在用户注销时删除Authorization HTTP 标头来解决

【讨论】:

【参考方案3】:

您还可以在登录时清除您的标头,然后再发送您的 POST 请求:

delete $http.defaults.headers.common['Authorization'];

【讨论】:

以上是关于Chrome 浏览器如何决定何时发送 OPTIONS?的主要内容,如果未能解决你的问题,请参考以下文章

如何检测用户何时在浏览器当前选项卡视口中放置图像?

如何检测用户何时浏览某个 url?

聊天应用程序如何知道用户何时发送消息以重新呈现?

如何使用nodejs向android chrome浏览器发送通知?

如何自定义网络通知?

如何让option中的文字居中