Chrome 浏览器如何决定何时发送 OPTIONS?
How does the Chrome browser decide when to send OPTIONS?
我有一个 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 ....
现已登录
我注销无非是把token去掉再重新登录。发生了一些不同的事情。之前它没有发送选项,但现在它发送了。之前的 request/response 是否会影响浏览器在我第二次登录时采取不同的行为?
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"}
如果我重置浏览器并重新加载页面,它会回到之前的状态,第一次不发送选项,我就可以登录了。
可能我需要更改服务器上的某些内容以便它处理选项。
但是为什么我的浏览器 (Chrome) 第一次没有发送选项?
Chrome(或任何其他浏览器)是否发送 OPTIONS 请求完全由 CORS specfication:
指定
When the cross-origin request algorithm is invoked, these steps must be followed:
...
2. If the following conditions are true, follow the simple cross-origin request algorithm:
The request method is a simple method and the force preflight flag is unset.
Each of the author request headers is a simple header or author request headers is empty.
3. Otherwise, follow the cross-origin request with preflight algorithm.
Note: Cross-origin requests using a method that is simple with author request headers that are not simple will have a preflight request to ensure that the resource can handle those headers. (Similarly to requests using a method that is not a simple method.)
您的 OPTIONS 请求包含以下请求 header:
Access-Control-Request-Headers: accept, <b>authorization</b>, content-type
这意味着您的 Angular 应用已插入非 simple Authorization
请求 header,可能作为身份验证方案的一部分。 Non-simple "author request headers" 触发 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。
当您第一次登录时,您很可能在登录过程的某处设置了 Authorization
HTTP header。另一方面,您忘记在用户注销时删除此 header。
当您尝试再次登录时,Authorization
HTTP header 仍然存在。这会触发浏览器执行预检请求(请参阅 Rob W 的解释:https://whosebug.com/a/27924344/548020。考虑到您尝试使用授权类型密码登录,发送 Authorization
[=23= 没有意义],因为这意味着您已经获得授权(=登录)。您基本上是在要求您的后端登录,同时告诉您的后端您已经获得授权(=登录)。
这可以通过在用户注销.
时简单地删除 Authorization
HTTP header 来解决
您还可以在登录时清理 Headers,然后再发送 POST 请求:
delete $http.defaults.headers.common['Authorization'];
我有一个 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 ....
现已登录
我注销无非是把token去掉再重新登录。发生了一些不同的事情。之前它没有发送选项,但现在它发送了。之前的 request/response 是否会影响浏览器在我第二次登录时采取不同的行为?
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"}
如果我重置浏览器并重新加载页面,它会回到之前的状态,第一次不发送选项,我就可以登录了。
可能我需要更改服务器上的某些内容以便它处理选项。
但是为什么我的浏览器 (Chrome) 第一次没有发送选项?
Chrome(或任何其他浏览器)是否发送 OPTIONS 请求完全由 CORS specfication:
指定When the cross-origin request algorithm is invoked, these steps must be followed:
...
2. If the following conditions are true, follow the simple cross-origin request algorithm:
The request method is a simple method and the force preflight flag is unset.
Each of the author request headers is a simple header or author request headers is empty.
3. Otherwise, follow the cross-origin request with preflight algorithm.
Note: Cross-origin requests using a method that is simple with author request headers that are not simple will have a preflight request to ensure that the resource can handle those headers. (Similarly to requests using a method that is not a simple method.)
您的 OPTIONS 请求包含以下请求 header:
Access-Control-Request-Headers: accept, <b>authorization</b>, content-type
这意味着您的 Angular 应用已插入非 simple Authorization
请求 header,可能作为身份验证方案的一部分。 Non-simple "author request headers" 触发 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。
当您第一次登录时,您很可能在登录过程的某处设置了 Authorization
HTTP header。另一方面,您忘记在用户注销时删除此 header。
当您尝试再次登录时,Authorization
HTTP header 仍然存在。这会触发浏览器执行预检请求(请参阅 Rob W 的解释:https://whosebug.com/a/27924344/548020。考虑到您尝试使用授权类型密码登录,发送 Authorization
[=23= 没有意义],因为这意味着您已经获得授权(=登录)。您基本上是在要求您的后端登录,同时告诉您的后端您已经获得授权(=登录)。
这可以通过在用户注销.
时简单地删除Authorization
HTTP header 来解决
您还可以在登录时清理 Headers,然后再发送 POST 请求:
delete $http.defaults.headers.common['Authorization'];