一、什么是 CORS
先从名称出发,Cross-Origin Resource Sharing (CORS) 翻译过来就是「跨域资源共享」,它是一个系统,它由一系列传输的 HTTP 头组成,这些 HTTP 头决定浏览器是否阻止前端 JavaScript 代码获取跨域请求的响应。 举一个跨域的例子: www.baidu.com/fetchData 使用 XHR 请求 www.qiandu.com/featchData
名词解释
- HTTP 头,它是服务端与客户端之间传递消息的附加信息,包括请求标头、响应标头、通用标头,实体标头,并且通常存在于 HTTP 请求的首部,格式是 header-name: header-value
- Origin,Web 内容的源由用于访问它的的方案 (协议),主机 (域名) 和端口定义。只有当协议,域名和端口都匹配时,这时就称为同源。
二、造成 CORS errors 的原因以及解决
原因有多种,比如:
- CORS 被禁用
- 服务端响应请求为重定向
- 协议不同,使用 http 去请求 https 的资源
- 服务端没有设置 'Access-Control-Allow-Origin' 标头的值或者不匹配
- Credential 不接受 http 响应标头中的 ‘Access-Control-Allow-Origin’ 设置为 ‘*’
- http 请求的方法与服务端设置的 'Access-Control-Allow-Method' 标头的值不匹配
- CORS 请求要求服务端设置 'Access-Control-Allow-Credential' 设置为 true,但是服务端并没有设置或者设置为 false
- CORS 预检请求失败
- 服务端设置了多个 'Access-Control-Allow-Origin' 标头的值,该标头只接受一个值
详情参考:CORS errors 汇总
三、为什么有 CORS errors
出于安全的考虑,浏览器限制从脚本中发出的跨域请求。例如 XHR 和 Fetch 都遵守同源策略。
四、什么是 CORS 预检请求
CORS 预检请求用于检查服务器是否支持 CORS 即跨域资源共享。 它一般是用了以下几个 HTTP 请求头的 OPTIONS 请求:Access-Control-Request-Method 和 Access-Control-Request-Headers,以及一个 Origin 标头。 当有必要的时候,浏览器会自动发出一个预检请求;所以在正常情况下,前端开发者不需要自己去发这样的请求。
五、为什么要有预检请求
跨源资源共享标准新增了一组 HTTP 头字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型 的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求,从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证 相关数据)。
六、什么情况下触发预检请求
先说说什么情况不会触发预检请求吧,也就是简单请求。
简单请求
⚠️注意:需要满足以下所有条件
- 使用下列方法之一
- GET
- POST
- HEAD
- 除了被用户代理自动设置的首部字段(例如 Connection、User-Agent)其他允许设置的标头集合:
- Accept
- Accept-Language
- Content-Language
- Content-Type(需要注意额外的限制)
- **Content-Type **的值仅限于下列三者之一:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
- 请求中的任意 XMLHttpRequest 对象均没有注册任何事件监听器;XMLHttpRequest 对象可以使用 XMLHttpRequest.upload 属性访问。
- 请求中没有使用 ReadableStream 对象。
如果不满足以上条件,那么 CORS 请求将自动变为预检请求