简要总结 CORS 和涉及的 HTTP 头,用于快速查阅,详情请查看 MDN 文档 🔍

What 定义

跨域资源共享(CORS),用于让网页的受限资源能够被其他域名的页面访问的一种机制。 通过该机制,页面能够自由地使用不同源的图片、样式、脚本、iframes以及视频。一些跨域的请求常常会被同源策略所禁止的。跨源资源共享定义了一种方式,为的是浏览器和服务器之间能互相确认是否足够安全以至于能使用跨源请求。

Why 目的

跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 XMLHttpRequest 或 Fetch )使用 CORS,以降低跨域 HTTP 请求所带来的风险

例如以下场景

  • 由 XMLHttpRequest 或 Fetch 发起的跨域 HTTP 请求
  • Web 字体
  • WebGL 贴图
  • 使用 drawImage 将 Images/video 画面绘制到 canvas

How 实现

跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。

三种控制场景

1. 简单请求

不会触发预检请求的请求,称为简单请求。简单请求满足以下条件

  • 使用这些方法: GET POST HEAD
  • 不人为干预以下首部:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
  • Content-Type 仅限:
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded

时序图
image.png

2. 预检请求

先发起一个请求到服务器,以获知服务器是否允许该实际请求,称为“预检请求”。使用预检请求可以避免跨域请求对服务器的用户数据产生未预期的影响

预检请求满足以下条件:

  • 方法是 PUT DELETE CONNECT OPTIONS TRACE PATCH
  • 人为干预以下首部:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
  • Content-Type 不属于
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded

时序图
image.png

3. 附带身份的请求

对于跨域 XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest 的某个特殊标志位,比如 withCredentials

发起附带身份的请求,想要获得数据必须满足

  • Access-Control-Allow-Origin 不得为 *
  • Access-Control-Allow-Credentials 必须为 true
  • 如果携带 Set-Cookie 字段,尝试对 Cookie 进行修改。如果操作失败,将会抛出异常

时序图
image.png

涉及的 HTTP 首部

请求(Request)

首部 含义
Origin 表明预检请求或实际请求的源站
Access-Control-Request-Method 用于预检请求,将实际请求所使用的 HTTP 方法告诉服务器
Access-Control-Request-Headers 用于预检请求,将实际请求所携带的首部字段告诉服务器

响应(Response)

首部 含义
Access-Control-Allow-Origin 指定了允许访问该资源的外域 URI
Access-Control-Expose-Headers 浏览器就能够通过 getResponseHeader 访问哪些首部的值
Access-Control-Max-Age 指定预检请求结果能够被缓存多久
Access-Control-Allow-Credentials 预检请求时,是否可以将对请求的响应暴露给页面
Access-Control-Allow-Methods 预检请求时,指明实际请求所允许使用的 HTTP 方法
Access-Control-Allow-Headers 预检请求时,指明实际请求中允许携带的首部字段

Tools CORS 代理服务器

以下代理服务器响应头均返回 Access-Control-Allow-Origin: *

用法举例(简单跨域请求)

  1. GET https://kuayu.herokuapp.com/https://exmaple.com/api
  2. GET https://icors.now.sh/?https://exmaple.com/api
  3. PS: https://exmaple.com/api/ 为不支持跨域的接口,经过转发后即可跨域。

对与简单请求,上述工具都能满足,对于预检请求,可以使用下面这个工具来检查请求和响应必须包含的首部字段。

用法举例(POST 预检请求)
**

  • 从 httptoolkit.tech 发送 POST 请求到 jsonbase.com/ifyour/demo
  • 发送 JSON 字符串, Content-Type 为: application/json

可以看到,注释部分列出了这些 Header,是不是很方便?🦄

image.png