乐趣区

关于前端:理论与实践相结合彻底理解CORS

关注公众号“执鸢者”,回复“红宝书”获取“javaScript 高级程序第四版(pdf)”及大量前端学习材料。

跨域问题始终是面试中的经典问题,不论是前端老鸟还是新鸟都碰到过。其中针对跨源 Ajax 申请中有一个终极解决办法——CORS(跨源资源共享)大家必定也不生疏,一说这个名词,咱们就会哗啦哗啦说进去一套又一套的理论知识,然而这些理论知识很多咱们做的仅仅是去背诵,很少去验证每一个实践点,本节咱们将通过试验的形式去验证这些实践点,通过实践与实际相结合的形式彻底了解 CORS。

一、理论知识

既然是 CORS,背背这些实践点必定不为过吧,我就用三幅图对这个实践进行一些简略的总结

1.1 申请类型

1.1.1 简略申请

1.1.2 非简略申请

1.2 申请如何带上 Cookie 信息

二、试验

为试验做好后期筹备工作,蕴含一个 html 页面和一个服务器程序,其中 html 拜访网址为 http://127.0.0.1:8009; 服务器监听端口为:8010.

  1. html 页面初始代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>test CORS</title>
    </head>
    <body>
        CORS
        <script src="https://code.bdstatic.com/npm/axios@0.20.0/dist/axios.min.js"></script>
        <script>
            axios('http://127.0.0.1:8010', {method: 'get'}).then(console.log)
        </script>
    </body>
</html>
  1. 服务器端代码(用 express 框架)
const express = require('express');

const app = express();

app.get('/', (req, res) => {console.log('get 申请收到了!!!');
    res.send('get 申请曾经被解决');
})
app.listen(8010, () => {console.log('8010 is listening')
});

2.1 试验一

试验目标:

  1. 非同源会产生跨域问题
  2. 跨域是浏览器对响应拦挡造成的
  1. 首先来看看浏览器控制台内容

控制台内容显示报错,报错内容是跨域,这是因为端口不同(一个 8009 一个 8010),两者不同源,所以导致跨域,验证了试验目标 1.

  1. 紧接着来瞅瞅服务器控制台打印了啥内容

控制台内容打印了接管到了 get 申请,则证实浏览器的申请收回了并被服务器端失常接管,从侧面证实了跨域是浏览器对响应进行了拦挡,从而验证了试验目标 2.

2.2 试验二

试验目标

  1. 服务器配置 Access-Control-Allow-Origin 会解决跨域问题
  2. 浏览器通过响应头中是否蕴含 Access-Control-Allow-Origin 这个响应头的值与申请头中 Origin 是否相等来确定是否可能进行跨域拜访
  1. 首先来搂一眼申请头

  1. 紧接着再来搂一眼响应头

依照实践来说,申请头中的 Origin 字段示意本次申请来自哪个源(协定 + 域名 + 端口),服务器依据这个值来决定是否批准这次申请。如果 Origin 指定的源不在许可范畴内,服务器会返回一个失常的 HTTP 回应。目前并没有批改,还处于报错状态,该响应的确是一个失常响应,不蕴含 Access-Control-Allow-Origin 字段,然而这也不足以压服我浏览器是通过验证该字段来的确是否容许跨域申请。所以紧接着须要做一个比照试验,通过批改服务端的代码后察看响应头内容。

  1. 从最简略的批改开始,间接将响应头中退出 Access-Control-Allow-Origin=“http://127.0.0.1:8009”字段,实践上来说此时会容许所有的跨域申请。

服务端代码批改后内容

app.get('/', (req, res) => {console.log('get 申请收到了!!!');
    res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:8009');
    res.send('get 申请曾经被解决');
})

响应头内容

察看到响应头中多了一行内容:Access-Control-Allow-Origin:http://127.0.0.1:8009 字段,在看看响应内容,的确有音讯返回了,内容如下:

  1. 只验证了 Origin 和 Access-Control-Allow-Origin 中内容响应,若内容不同又会有什么景象呢?

服务端代码进一步批改

app.get('/', (req, res) => {console.log('get 申请收到了!!!');
    res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:8008');
    res.send('get 申请曾经被解决');
})

响应头内容

此时浏览器控制台报错了,呈现了跨域问题

通过该试验能够验证通过配置 Access-Control-Allow-Origin 字段能够解决跨域问题;此外,浏览器是通过查看响应头中 Access-Control-Allow-Origin 字段的值与 Origin 的值是否相等来确定是否容许跨域拜访的。通过该试验达到了咱们试验的目标。

2.3 试验三

试验目标
验证 CORS 申请默认不发送 Cookie 信息,如果要把 Cookie 发送到服务器,一方面要服务器批准(通过指定 Access-Control-Allow-Origin 字段且 Access-Control-Allow-Origin 须要指定具体域名);另一方面浏览器申请中必须带上 withCredentials 字段。

  1. 通过观察申请头(看试验一中申请头),并不蕴含 Cookie 信息
  2. 代码批改

index.html 页面进行批改

axios('http://127.0.0.1:8010', {
    method: 'get',
    withCredentials: true
}).then(console.log)

服务器端代码批改

app.get('/', (req, res) => {console.log('get 申请收到了!!!');
    console.log('cookie 内容为', req.headers.cookie);
    res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:8009');
    res.setHeader('Access-Control-Allow-Credentials', true);
    res.cookie('test', 'test', {expires: new Date(Date.now() + 900000)});
    res.send('get 申请曾经被解决');
})
  1. 再次察看申请头内容,带上了 cookie

  1. 看看服务器端有没有接管到 cookie 信息,控制台信息如下,的确收到了 cookie 信息

依照上述进行配置发送申请过程中将会带着 cookie 信息,上一个配置将会报错(能够自行验证)

2.4 试验四

试验目标

  1. 验证非简略申请会减少一次预检申请
  2. 预检申请是 Options 申请
  3. 申请头中会携带非简略申请的申请办法(Access-Control-Request-Methods)和头信息(Access-Control-Request-Headers),预检申请的响应头信息中 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers 与上述申请头中的信息匹配才能够发送失常的 CORS 申请。
  1. 第一步必定是要批改代码了

index.html 代码

axios('http://127.0.0.1:8010', {
    method: 'post',
    headers: {'Content-Type': 'application/json'},
    data: {name: 'dog'}
}).then(console.log)

服务器代码批改如下

app.options('/', (req, res) => {console.log('options 申请收到了!!!');
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
    res.setHeader('Access-Control-Max-Age', 10000);
    res.send('options 申请曾经被解决');
});

app.post('/', (req, res) => {console.log('post 申请收到了!!!');
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.send('post 申请曾经被解决');
});
  1. 批改完了代码是不是要瞅瞅后果呢?

先看看浏览器是不是输入了内容, 的确有内容输入了

再瞅瞅服务器输入了些什么内容

能够看到原本打算发一次申请,但实际上发了两条,第一条是 Options 申请,第二条申请才是 post 申请,上述打印内容验证了试验目标中的一和二。

  1. 上面持续深刻思考,来看看预检申请的申请头和响应头

申请头内容

响应头内容

上述 Access-Control-Request-Headers 与 Access-Control-Allow-Headers 一样,而且内容也失常返回了(步骤二中曾经进行了展现),然而这不足以证实试验目标三,上面咱们认为减少一条头信息再来看后果。

  1. 人为减少一条申请头信息

index.html 页面批改后如下

axios('http://127.0.0.1:8010', {
    method: 'post',
    headers: {
        'Content-Type': 'application/json',
        'Test': 'test'
    },
    data: {name: 'dog'}
}).then(console.log)

此时浏览器控制台报错了

服务端只接管到了 options 申请

申请头信息为

响应头信息为

通过该试验证实只有 Access-Control-Request-Headers 与 Access-Control-Allow-Headers 相等的时候,预检申请才会通过,后续申请才会收回,从而达到了该试验的试验目标三。

1. 如果感觉这篇文章还不错,来个分享、点赞吧,让更多的人也看到

2. 关注公众号执鸢者,支付学习材料,定期为你推送原创深度好文

退出移动版