关于浏览器CORS你很可能还不知道的那些事

198 阅读4分钟

一、引子

在实际的业务开发中,在接口服务端已经支持CORS的情况下, 你的浏览器上可能还是会出现跨域的报错。

接口服务端已经支持CORS相关response-headers: 企业微信截图_df4e3fbb-44ce-473c-becc-4eba53490c45.png 但是还是发现浏览器请求会报跨域的错: 企业微信截图_eebb53cd-e764-4a16-a731-af87a247304c.png 这是为什么呢???

二、让我们复习一下CORS的知识点

1.CORS定义

CORS 是 "Cross-Origin Resource Sharing" 的缩写,中文翻译为 "跨域资源共享"。CORS 是一种浏览器机制,它允许受限资源(如字体、JavaScript)在一个域上被另一个域访问。它通过在 HTTP 头部中使用一组新的 HTTP 头部来实现,这些头部允许服务器声明哪些源站点有权限访问它们的资源。

2.CORS 通过以下 HTTP 头部来实现:

请求头部:
Origin: 指示请求的来源(协议、域名和端口)。
Access-Control-Request-Method: 在预检请求中使用,指示实际请求将使用的方法。
Access-Control-Request-Headers: 在预检请求中使用,指示实际请求将使用的自定义头部。
响应头部:
Access-Control-Allow-Origin: 指示哪些来源可以访问资源。可以是具体的域名,也可以是通配符 *。
Access-Control-Allow-Methods: 指示允许的 HTTP 方法(如 GET、POST、PUT、DELETE)。
Access-Control-Allow-Headers: 指示允许的自定义头部。
Access-Control-Allow-Credentials: 指示是否允许发送 Cookie。
Access-Control-Expose-Headers: 指示哪些头部可以在响应中暴露给浏览器。
Access-Control-Max-Age: 指示预检请求的结果可以缓存多长时间

Access-Control-Allow-Origin这个header参数大家都很熟悉,但是很多人会忘记或不知道其实还有Access-Control-Request-MethodAccess-Control-Request-Headers这两个头。

那他们是做什么的呢?这就涉及到了CORS设计中两个很重要点概念:简单请求非简单请求

三、 简单请求options预检请求

在 HTTP/1.1 中,当使用某些方法(如 POST、PUT、PATCH)发送跨域请求时,如果请求包含自定义头部(如 Content-Type 设置为非默认值),浏览器会先发送一个预检请求(OPTIONS 请求)来检查服务器是否允许该实际请求。这是 CORS(跨域资源共享)规范的一部分,用于确保跨域请求的安全性。

预检请求的触发条件

1.使用了非简单方法(如 PUT、DELETE、PATCH)。
2.使用了非简单头部(如 Content-Type 设置为application/json等)。
3.请求包含自定义头部。

简单请求的条件

如果请求满足以下条件,则不会触发预检请求:

1.使用简单方法(GET、POST、HEAD)。
2.使用简单头部:
    Accept
    Accept-Language
    Content-Language
    Content-Type(值为 application/x-www-form-urlencoded、multipart/form-data 或 text/plain)
3.请求不包含自定义头部。

四、Content-Type与COSR对options预检策略的关系

设置 Content-Type 为 application/x-www-form-urlencoded 通常不会触发预检请求的原因是,浏览器将这种请求视为“简单请求”。根据 CORS(跨域资源共享)规范,简单请求不会触发预检请求(OPTIONS 请求)。

简单请求的条件

使用简单方法:GET、POST、HEAD。
使用简单头部:
    Accept
    Accept-Language
    Content-Language
    Content-Type(值为 application/x-www-form-urlencoded、multipart/form-data 或 text/plain)
请求不包含自定义头部。

为什么不设置 Content-Type 可能会触发预检请求

当你不显式设置 Content-Type 时,浏览器可能会根据请求体的内容自动推断并设置 Content-Type。如果浏览器自动设置的 Content-Type 不符合简单请求的条件(例如,设置为 application/json),则会触发预检请求。

五、结论

1.浏览器CORS的设计是为了保证后台接口服务点安全性,不仅仅只是对请求发起方页面所在域名进行了限制;还会限制跨域请求的请求方法、携带的自定义头部等进行限制。

2.对跨域请求的请求方法、携带的自定义头部等进行限是基于options的预先请求机制来实现的。

3.因为历史原因浏览器设计了简单请求概念,对跨域下满足简单请求的请求不用进行option的提前安全校验,因为简单请求的风险很低、在服务端的安全策略也很完善,浏览器对他们开了绿灯。

4.不满足简单请求的请求 必须要先走options预请求校验其安全性。