JesseZhao1990 / blog

learing summary
MIT License
62 stars 7 forks source link

CORS #18

Open JesseZhao1990 opened 6 years ago

JesseZhao1990 commented 6 years ago

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS#Preflighted_requests

JesseZhao1990 commented 6 years ago

场景回顾

某天,正在能跨域访问的接口开始拒绝访问,经排查,从接受访问和拒绝访问中间只发生了一件事,那就是在请求头中添加了一个字段(x-trace-id)。为什么请求头中添加了一个普普通通的字段就不能跨域了呢??

HTTP访问控制(CORS)

当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。

跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求,浏览器必须首先使用 options方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。

什么条件会触发预检请求呢?触发的条件有很多。但是其中有一条规则是这样的:人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合在下面截图中列出,由于自定义的一个字段不match下图列出的任何一项,所以会触发预检请求。

001

发起预检查之后,服务端并没有接受这样的请求

002

从图中可以看到,

预检请求中同时携带了下面两个首部字段:

Access-Control-Request-Headers: x-trace-id

Access-Control-Request-Method: POST

首部字段 Access-Control-Request-Method 告知服务器,实际请求将使用 POST 方法。首部字段 Access-Control-Request-Headers 告知服务器,实际请求将携带两个自定义请求首部字段:x-trace-id 。服务器据此决定,该实际请求是否被允许

由于服务器的相应没有携带这条信息:Access-Control-Request-Headers: x-trace-id ,所以表明服务器预检失败。浏览器认为服务器拒绝此跨域请求。所以不再发起下面的实际请求。

解决办法

如果此跨域请求的请求头没必要携带自定义的字段,那就不再携带即可。 服务端设置,在预检请求的响应值中添加接受请求头的自定义字段 x-trace-id

nginx配置

如果服务端用的是nginx,可以给某一个loaction或者所有的http请求的响应头添加Access-Control-Allow-Origin,Access-Control-Allow-Headers,Access-Control-Allow-Methods 即可,以下是一个示例:


http {
......
add_header Access-Control-Allow-Origin 你允许跨域的域名;
add_header Access-Control-Allow-Headers x-trace-id,X-TRACE-ID;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
......
}