浅谈CORS

244 阅读3分钟

同源概念

为了保证用户信息的安全,防止恶意的网站窃取数据,现行所有浏览器都实行 “同源策略”。 同源是指:协议相同、域名相同、端口相同

但是在实际应用中,我们常常需要向非同域站点发送请求,这个时候就需要应用到 “CORS” 来解决跨域问题了

CORS(跨域资源共享)

CORS是一个W3C标准,全称是 “跨域资源共享”(Cross-origin resource sharing)

它允许浏览器向跨域服务器发起 XMLHttpRequest请求,从而解决同源限制问题

CORS请求: 简单请求、非简单请求

简单请求

同时满足以下条件,即属于简单请求:

  1. 请求方法是以下三种方法之一:
  • HEAD
  • GET
  • POST
  1. HTTP 的头信息不超出以下几种字段
  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type: 只限于 (application/x-www-form-urlencoded、multipart/form-data、text/plain)

复杂请求

非简单请求既是复杂请求

常见的复杂请求有:

  1. 请求方法为put或delete
  2. Content-Type字段类型为application/json
  3. 添加额外的HTTP Header,比如access_token

在跨域的情况下,复杂请求会先发起一次空body的OPTIONS请求,称为 “预检” 请求(preflight),用于向服务器发送请求权限信息,等预检请求被成功响应后(这里的成功不是有响应,而是返回的响应体允许跨域),才会再次发起真正的http请求

预检请求

非简单请求的CORS请求,会在正式通信之前,增加一次空body的HTTP查询OPTIONS请求,称为"预检"请求(preflight)

预检请求的请求体是空的,这样做是为了节约带宽,提高传输速率

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP方法和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错

预检请求的头信息包括以下几个必须的特殊字段:

  • Origin:表示请求来自哪个源
  • Access-Control-Request-Method:本次预检请求的请求方法
  • Access-Control-Request-Header:本次请求所携带的自定义首部字段,该字段是一个逗号分隔的字符串

预检请求响应头

服务端收到预检请求后,检查了请求头的几个字段之后,便可以做出相应的回应:

// 服务器返回的响应头
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
  • Access-Control-Allow-Methods

    必须字段,是一段由逗号分隔的字符串,表示服务器支持的所有跨域请求的方法 (是所有支持的方法,而不是浏览器请求的方法,这是为了避免重复预检请求)

  • Access-Control-Allow-Headers

    如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段

  • Access-Control-Allow-Credentials

    该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可

  • Access-Control-Max-Age

    该字段可选。用来指定本次预检请求的有效期 (即对预检请求进行缓存)

在预检请求跨域通过时,在后续的CORS请求中。请求头总会有一个Origin字段,而服务器的响应,也都会有一个Access-Control-Allow-Origin字段

其他常见跨域解决方案

  • JSONP

  • CORS

  • iframe

  • postMessage

  • websocket

  • nginx代理

  • 中间件代理