请求头

浏览器会自动帮你先发出一个叫做预检(cors-preflight-request)的请求, 对应的 HTTP Request Method 为 OPTIONS。这个请求对服务器是安全的,也就是说不会对服务器的资源做任何改变,仅仅用于确认 header 响应

该请求 header 中会包含以下两个字段:

  • Access-Control-Request-Method: 该字段的值对应当前请求类型,例如 GET、POST、PUT等等。浏览器会自动处理。
  • Access-Control-Request-Headers: 该字段的值对应当前请求可能会携带的额外的自定义 header 字段名,多个字段用逗号分割。浏览器会自动处理,将请求中非简单的 header 字段全部列出来,例如标识请求流水的 x-request-id,用于 Auth 鉴权的 Authorization 字段。

对于 OPTIONS 请求,按照规范实现的服务端会响应一组HTTP header,但不会返回任何实体内容。如果服务端支持该跨域请求,建议返回 204 状态码(返回 200 也可以)。如果不支持,建议返回 403 状态码(返回 404 或其他错误状态码也可以)。

响应的 header 可以包含以下字段:

  • Access-Control-Allow-Origin: 允许哪些域被允许跨域,例如 http://qq.comhttps://qq.com,或者设置为 * ,即允许所有域访问(通常见于 CDN )
  • Access-Control-Allow-Credentials: 是否携带票据访问(对应 fetch 方法中 credentials),当该值为 true 时,Access-Control-Allow-Origin 不允许设置为 *
  • Access-Control-Allow-Methods: 标识该资源支持哪些方法,例如:POST, GET, PUT, DELETE
  • Access-Control-Allow-Headers: 标识允许哪些额外的自定义 header 字段和非简单值的字段(这个后面会解释)
  • Access-Control-Max-Age: 表示可以缓存 Access-Control-Allow-MethodsAccess-Control-Allow-Headers 提供的信息多长时间,单位秒,一般为10分钟。
  • Access-Control-Expose-Headers: 通过该字段指出哪些额外的 header 可以被支持。

发送流程

  1. 当我们发起跨域请求时,如果是非简单请求,浏览器会帮我们自动触发预检请求,也就是 OPTIONS 请求,用于确认目标资源是否支持跨域。如果是简单请求,则不会触发预检,直接发出正常请求。

  2. 浏览器会根据服务端响应的 header 自动处理剩余的请求,如果响应支持跨域,则继续发出正常请求,如果不支持,则在控制台显示错误。

简单请求

  • 请求方法必须是以下之一:GET、HEAD、POST,也就是说 PUT、PATCH 等方法必然会触发预检。

  • 只有以下 header 字段允许被修改或被设置,否则必然触发预检。

    • AcceptAccept-LanguageContent-languageContent-Type(但有限定值)、DPRDownlinkSave-DataViewport-WidthWidth
    • Content-Type 的值只被允许设置为以下三个之一:application_x-www-form-urlencodedmultipart_form-datatext/plain。也就是说,如果请求的 Content-Type 被设置为 application/json;charset=utf-8 时也必然会触发预检。
    • 添加任何额外的自定义的 header 都会触发预检,例如 x-request-id,但服务端可以设置缓存这一个请求的OPTIONS 响应。
  • XMLHttpRequestUpload 在请求中使用的任何对象上都没有注册事件侦听器。这个比较少见。

  • ReadableStream 请求中未使用任何对象。这个比较少见,应该是指 Fetch API 中的 Request 中的 Body,本人没有去验证。

也就是说带有 Auth 鉴权的 Authorization 字段也非简单请求。

CDN引用

  1. <script src="https://qq.com/a.js" crossOrigin="anonymous"></script>

CDN 设置了 Access-Control-Allow-Origin响应头允许跨域时,我们可以给script标签添加crossOrigin属性,从而可以使用 window.onerror 捕获 CDN 上的 js 运行时导致的详细错误信息,包括堆栈等。

如果不设置crossOrigin属性,则可能只会捕获到script error,无法获取额外的堆栈信息。