跨域方法之CORS

219 阅读2分钟

简介

CORS 全称:跨域资源共享(Cross-origin resource sharing),主要用来解决由于同源策略导致的 XMLHttpRequest 和 Fetch 无法获取请求资源的问题。

这里以 XMLHttpRequest 为例,server 端以 express 框架为例

分类

浏览器将CORS请求分成两类:简单请求和非简单请求。只要同时满足以下两大条件,就属于简单请求:

1.请求方法是以下三种方法之一:

  • head
  • get
  • post

2.请求头不超出以下几种字段:

  • accept
  • accept-language
  • content-language
  • content-type:只限于三个值,application/x-www-form-urlencoded、multipart/form-data、text/plain

非简单请求:当不符合上面的条件时,就是非简单请求。

解决办法

简单请求:只需要在 server 端设置请求头:

res.header('Access-Control-Allow-Origin', '*'); //或者相应的origin

非简单请求:

非简单请求会在正式通信之前,会增加一次 options 查询请求,称为"预检"请求(preflight)。这时想要实现跨域资源共享,除了 origin 外,还要设置其他属性:

let xhr = new XMLHttpRequest(),
    method = 'post',
    url = 'http://127.0.0.1:3000/getData';

xhr.open(method, url, true);
// 自定义头部
xhr.setRequestHeader('X-requestId', '123456');
xhr.send({ form: 'data' });
xhr.onreadystatechange = function () {
  if(xhr.readyState === 4) {
    console.log('success')
  }
}

比如我在代码中设置了一个自定义的头部,那么此时就需要在 server 设置:

res.header('Access-Control-Allow-Headers', 'X-requestId');

除此之外,因为我们设置跨域一般都是统一设置,因此,可以加上这个:

res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); // 这里包括你项目中各种请求方法

cookie的问题

在跨域时,想带上 cookie 需要设置:

// 前端:
xhr.withCredentials = true;

// server端
res.header('Access-Control-Allow-Credentials', true);

注意事项:

  • 携带 cookie 时,Access-Control-Allow-Origin 字段必须为前端请求的origin,不能是 “*”
  • 前端无法获取和修改 server 端种到本地的 cookie
  • 在 chrome 浏览器里,cookie 也不会出先在请求头中(不跨域时是有的)
  • 普通请求如果携带 cookies, 也不会触发“预检”请求

XMLHttpRequest

CORS请求时,XMLHttpRequest 对象的 getResponseHeader() 方法只能拿到6个基本字段:

  • Cache-Control、
  • Content-Language、
  • Content-Type、
  • Expires、
  • Last-Modified、
  • Pragma。

如果想拿到其他字段,就必须在服务端 Access-Control-Expose-Headers 里面指定,例如:

res.header('Access-Control-Expose-Headers', 'X-requestId')

参考链接: