CORS 跨域请求的简单、复杂请求

216 阅读3分钟

开始之前先来复习一下同源策略叭,虽然米娜桑都会了😈

同源策略: 浏览器请求中 协议 | 域名 | 端口 保持一致时为同源,否则为跨域。域名 !== IP,所以部署在同一台服务器不同虚拟机上的 url 访问也是跨域。

🚩 注意:跨域请求失败不是请求发送不出去,服务器可以接收到请求,但是返回信息后浏览器截胡了,所以同源策略是浏览器的限制,比如打开 terminal 发送是不存在跨域问题的~

👉 附上大佬的跨域请求 9 种解决方案:juejin.cn/post/684490…

CORS(Cross-Origin Resource sharing)跨域资源共享

来自 MDN 的一段定义:

image.png

CORS 在 简单请求 时直接发起请求,请求头、响应头添加特定的字段,复杂请求 在正式发送前会加一个 预检 请求,我们来看下这两个请求有什么区别,CORS 需要校验哪些头字段👇

判断依据:满足以下条件时属于简单请求,否则为复杂请求👇

  1. method 属于以下三种之一: GET | HEAD | POST
  2. 允许人为设置的字段不能超出以下几种:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type 限于以下几种:
      • text/plain
      • multipart/form-data
      • application/x-www-form-urlencoded

简单请求

请求头必须带 origin 字段:

origin: https://juejin.cn
  • 如果该 origin 不在白名单内,则会抛出错误,返回信息被 XMLHttpRequest 捕获输出到 onerror 回调中,不过返回状态码依然是 200。
  • 如果该 origin 在白名单内,服务器除了 Access-Control-Allow-Origin ,还会返回以下响应头:
    Access-Control-Allow-Origin: https://juejin.cn | * // 非请求头 origin | * 则服务器拒绝
    Access-Control-Allow-Credentials: true // 是否允许携带 cookie
    Access-Control-Expose-Headers: custom-header // 服务器允许客户端发起的自定义字段
    Content-Type: text/plain; charset=utf-8 // Content-Type 非上述三类之一便变成了复杂请求
    
    • Access-Control-Allow-Credentials 是服务器的态度,但拥有方是客户端,所以是否会携带还是要浏览器发起端设置 withCredentials 的值
      const invocation = new XMLHttpRequest();
      invocation.withCredentials = true;
      

复杂请求

预检请求(preflight)

该请求是 OPTION 请求,目的是在正式发起请求之前确认将要发的请求头是否在服务器支持范围内,若符合,则再发起正式请求,否则报错。此步骤用户无感知,是浏览器自动发起处理的。

预检请求会增加以下 3 个字段👇

origin: https://juejin.cn
Access-Control-Request-Method: GET
Access-Control-Request-Headers: custom-header

响应头也会回复对应字段👇

Access-Control-Allow-Origin: https://juejin.cn
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: custom-header
Access-Control-Max-Age: 200 // 单位: s 预检请求有效期,有效期内不需要再次发起预检,可像简单请求一样发起

预检请求通过后,正式请求发起,这次请求类似于简单请求,将在简单请求头基础上添加被允许的自定义请求头。

既然谈到请求头 origin,就想到了孪生兄弟👇

image.png

HTTP Referer

referer 将带上当前源页面 url,包括 path、query,但不包含 hash。具体规则要看 Referrer-Policy 设定以及不同浏览器的实现。可参考 MDN 定义:developer.mozilla.org/en-US/docs/…

  • 其次,a 标签的 rel 字段也可以设定 noreferrer

    <a rel="noreferrer" >
    
  • <meta> 标签中 也可以设定

    <meta name="referrer" content="origin"/>
    

image.png

有什么用

  1. csrf 攻击中,防止伪装请求,可通过 referer 字段判断
  2. 防盗链判断依据,当然服务器代理可伪装
  3. 埋点分析,path 暴露更多用户行为,粒度更细

缺点

因为包括详细的 path、query,也同样暴露了信息,使得部分隐私暴露

如何控制

参考 MDN 和优秀大佬的文章:

CORS: developer.mozilla.org/en-US/docs/…

学习 HTTP Referer: juejin.cn/post/713003…