站点图标 久久日记本

CORS跨域请求中Preflight Request

1.简述

HTTP RequestMethod参数中除了常见的POST,GET,DELETE等,还有个叫做OPTIONS的方法。

在MDN中这样描述:

HTTP 的 OPTIONS 方法 用于获取目的资源所支持的通信选项。客户端可以对特定的 URL 使用 OPTIONS 方法,也可以对整站(通过将 URL 设置为“*”)使用该方法。

检测服务器所支持的请求方法:

可以使用 OPTIONS 方法对服务器发起请求,以检测服务器支持哪些 HTTP 方法:

CORS 中的预检请求:

在 CORS 中,可以使用 OPTIONS 方法发起一个预检请求,以检测实际请求是否可以被服务器所接受。
预检请求报文中的 Access-Control-Request-Method 首部字段告知服务器实际请求所使用的 HTTP 方法;
Access-Control-Request-Headers 首部字段告知服务器实际请求所携带的自定义首部字段。
服务器基于从预检请求获得的信息来判断,是否接受接下来的实际请求。

2.实践

本站的Dict站点在请求Garden站点托管的API时使用了axios封装的ajax请求。

因为分属不同的二级域名,在 CORS 中,可以使用OPTIONS方法发起一个预检请求。但是在axios的跨域Preflight Request中,无法携带cookie,后端Flask API取不到值,导致验证报不通过,401错误。

检索了一下资料,并未找到很好的解决的方法。

干脆在验证的过程中,判断方法是否为OPTIONS,如果是,直接返回成功通过预检来解决这个问题。

if request.method == 'OPTIONS':
    # axios中http预请求拿不到cookie
    return None

考虑到安全风险,可以加上白名单限制吧。

3.CORS请求头与响应头

对于跨域,我们还需要在API response中设置类似下面的响应头,浏览器才不会拦截:

"Access-Control-Allow-Methods": "OPTIONS,GET,POSTxxxx",
"Access-Control-Allow-Headers": "Content-Type,Authorization",
"Access-Control-Allow-Origin": xxxx,
"Access-Control-Allow-Credentials": True,

2022-05-27更新:

从Chrome v102 开始,Google尝试实验在跨域请求的预检中,即Preflight的Request会带上请求头:

Access-Control-Request-Private-Network: true

请求跨域请求预检的Response返回是也要带相应的响应头:

Access-Control-Allow-Private-Network: true

经过测试发现Chrome v101不会带上该请求头,而 Chrome v102 版本开始携带了该请求头,会在没有实现该请求头的预检中提示错误信息。

Firefox 目前为100版本,尚未强制添加该请求头和要求添加响应头。

相信有不少使用了AWS Lamaba作为API且未绑定域名的同学,这个周五搞不好要加班来修正了。😀

4.参考资料

OPTIONS

Preflight request + cookie

Private Network Access: introducing preflights

本文最后更新:2022-05-27

退出移动版