HTTP预检(preflight)请求是在跨域请求(CORS)发起之前由浏览器自动发起的检查服务器是否支持跨域,以及确定服务器端跨域请求支持的方法和路径的流程。

MDN跨域资源共享 其实是一种资源保护的手段,防止第三方的站点调用未授权的接口。

OPTIONS请求在服务端没有配置CORS的情况下不会在浏览器网络面板显示,需要通过抓包查看。

如打开浏览器调试工具,执行fetch和post方法,可抓包看到OPTIONS请求。

fetch("https://httpbin.org/post",
{
  "headers": {
    "accept": "application/json",
    "content-type": "application/json;charset=UTF-8"
  },
  "body": "{\"username\":\"admin\",\"password\":\"111111\"}",
  "method": "POST"
}).then(console.log);

抓包看到
请求:

OPTIONS https://httpbin.org/post HTTP/1.1
Host:	httpbin.org
Connection:	keep-alive
Access-Control-Request-Method:	POST
Access-Control-Request-Headers:	content-type
Origin:	chrome-search://local-ntp
User-Agent:	Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36
Accept-Encoding:	gzip, deflate, br
Accept-Language:	en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7

返回值:

HTTP/1.1 200 OK
Access-Control-Allow-Credentials:	true
Access-Control-Allow-Headers:	content-type
Access-Control-Allow-Methods:	GET, POST, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Origin:	chrome-search://local-ntp
Access-Control-Max-Age:	3600
Allow:	OPTIONS, POST
Content-Type:	text/html; charset=utf-8
Date:	Mon, 03 Jun 2019 02:35:10 GMT
Referrer-Policy:	no-referrer-when-downgrade
Server:	nginx
X-Content-Type-Options:	nosniff
X-Frame-Options:	DENY
X-XSS-Protection:	1; mode=block
Content-Length:	0
Connection:	keep-alive

浏览器会根据返回的Access Control 信息判断是否发出真正的post请求。这是浏览器端的安全限制。有时候明明服务端实现了POST的API,通过postman测试也成功返回响应信息,但浏览器就是无法请求成功。postman不理会CORS的限制,并不会发送预检请求。

什么情况下跨域不会触发CORS预检?

GET,HEAD或POST且content-type的值仅限于下列三者之一:

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

除了上面三种情况外都会触发预检,所以发送一个content-type为application/json的post请求会触发CORS预检,而text/plain不会触发。所以可以通过修改content-type的值为text/plain规避CORS的问题。

怎样开放CORS跨域请求的限制?

https://enable-cors.org/server.html

启用 ASP.NET Web API 2 中的跨域请求

或者使用反向代理将非同源的地址与静态资源放在同一个域名下,这样就避免了跨域。

怎样测试?通过curl发起带Access-Control-Request-Method和Access-Control-Request-Headers和Origin的OPTIONS请求,这3个请求头对于ASP.NET CORS是必须的,不然会返回405 Method Not Allowed。

curl -X OPTIONS "http://httpbin.org/post" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: content-type" -H "Origin: chrome-search://local-ntp" -i
>HTTP/1.1 200 OK
>Access-Control-Allow-Credentials: true
>Access-Control-Allow-Headers: content-type
>Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, >OPTIONS
>Access-Control-Allow-Origin: chrome-search://local-ntp
>Access-Control-Max-Age: 3600
>Allow: POST, OPTIONS
>Content-Type: text/html; charset=utf-8
>Date: Mon, 03 Jun 2019 07:19:45 GMT
>Referrer-Policy: no-referrer-when-downgrade
>Server: nginx
>X-Content-Type-Options: nosniff
>X-Frame-Options: DENY
>X-XSS-Protection: 1; mode=block
>Content-Length: 0
>Connection: keep-alive
原文链接:https://marskid.net/2019/06/03/http-cors-and-options-method/