跨域解决方案之CORS

388 阅读5分钟

跨域的解决方案有很多,但是CORS是最正统的解决方案,也是官方推荐使用的方案,我们上文讲到同源策略的时候,讲到对异源请求做出的限制,在跨域请求中浏览器向服务器发出请求,服务器给出响应到浏览器的时候,浏览器会做一个校验,如果通过,就会把响应正常给JS,如果不通过,则会引发一个错误,这个错误就是跨域问题。而浏览器做的这个校验的规则就是CORS规则。所以使用CORS解决跨域问题无非就是让浏览器通过这个校验,这么一来就没有跨域问题了。

所以我们先要了解一下这个CORS规则。

什么是CORS规则?

CORS规则很简单,它的基本理念就是让服务器表个态,只要服务器明确表示允许,则校验就会通过;如果服务器明确拒绝或者没有表示,那么校验就不会通过。从这个理念里可以看出要用CORS解决跨域问题,主要靠服务器,如果让一个前端在页面上用CORS去解决跨域问题那就是纯扯淡,必要要让服务器参与。

使用CORS去解决跨域问题的前提是:服务器得是自己人,就是我们得能够操控服务器。比如我在自己的页面上访问淘宝会跨域,总不能让马云去让服务器使用CORS去解决问题。

CORS具体的做法

CORS将请求分为两类,一种是简单请求,另外一种是预检请求。我们首先要认识它是怎么分类的,因为不同类别的请求,它的规则会有所差异。其实只要认识简单请求就可以了,因为只要不是简单请求那么它就是预检请求。

1.什么是简单请求和预检请求

简单请求的条件:

  • 请求方法必须是GET、HEAD、POST请求之一。
  • 请求头部必须要满足CORS安全规范,详情参考W3C的官网。绝大部分情况只要不去修改头部那么就满足安全规范。
  • 请求头的Content-Type为以下三个之一:1. text/plain 2.multipart/form-data 3.application/x-www-form-urlencoded

预检请求:除了简单请求其他都是预检请求。

看几个例子:

// 1
fetch("https://douyin.com");

// 2
fetch("https://douyin.com", {
  headers: {
    a: 1,
  },
});

// 3
fetch("https://douyin.com", {
  method: "POST",
  body: JSON.stringify({ a: 1, b: 2 }),
});

// 4
fetch("https://douyin.com", {
  method: "POST",
  headers: {
    "content-type": "application/json",
  },
  body: JSON.stringify({ a: 1, b: 2 }),
});

第一个不用看就知道是简单请求。

第二个我们放到控制台去看一下:

image.png

1737040245672.png

看到这里是GET方法,但是然后后面加上了一个预检,说明这是一个预检请求,因为我们修改了请求头。

第三个没有修改请求头,也没有修改Content-Type,还是POST请求,所以这是个简单请求。

image.png

第四个修改了Content-Type,所以是个预检请求。

image.png

2. 怎么让简单请求通过校验

在发送简单请求跨域的时候,浏览器发现请求跨域了,就会自动给请求带上一个请求头,这个我们不用管也改不了,这个请求头就是Origin,通常表达是当前的页面源,也就是哪个页面发送的跨域请求。

1737041735544.png

那么怎么才能让简单请求通过校验呢?一般有两种方案。

第一种方案就是服务器给它一个响应头Access-Control-Allow-Origin,它的值也是一个源,表示是允许跨域的页面源,如果该源和请求头Origin的源相同,浏览器一看这两个源相同,是自己人,那就给通过了。第二种方案就是响应头Access-Control-Allow-Origin的值是一个*号,表示所有的源都给通过,那么浏览器也会通过这个校验。

image.png

3. 怎么让预检请求通过校验

发送预检请求跨域的时候,浏览器会对其高度重视,所以在第一步不会真实的发送这个请求,而是先来一个询问,就是浏览器先问一下服务器,我这边有一个页面源在跨域请求你,但是怕这个请求不安全,所以先问一下你能不能请求,如果可以我就真实的发送那个请求。预检请求的方法为OPTIONS,会带上三个请求头:

  • Origin:就是简单请求的那个,表示是哪个页面源发送的请求。
  • Access-Control-Request-Method:表示请求的方法是哪个。
  • Access-Control-Request-Headers:表示这次请求改动了哪些请求头。

然后服务器会给一个响应,其中有四个响应头:

  • Access-Control-Allow-Origin:表示允许发送跨域请求的页面源。
  • Access-Control-Allow-Methods:表示允许发送跨域请求的请求方法,可以有多个。
  • Access-Control-Allow-Headers:表示允许发送的跨域请求能够修改哪些请求头。
  • Access-Control-Max-Age: 表示这段时间内只要来自这个源的请求都不要再问了,都是这套回答,浏览器可以缓存下来。

image.png

服务器允许发送以后,浏览器就会发送真实请求,这个就跟简单请求完全一样。

image.png

总的来说CORS解决跨域问题的关键,就是服务器按照浏览器发送的请求头的信息,对相应的响应头做出设置就可以了。