理论与实践相结合完全理解CORS

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

跨域问题一直是面试中的经典问题,不论是前端老鸟仍是新鸟都碰到过。其中针对跨源Ajax请求中有一个终极解决办法——CORS(跨源资源共享)你们确定也不陌生,一说这个名词,咱们就会哗啦哗啦说出来一套又一套的理论知识,可是这些理论知识不少咱们作的仅仅是去背诵,不多去验证每个理论点,本节咱们将经过实验的方式去验证这些理论点,经过理论与实践相结合的方式完全理解CORS。html

1、理论知识

既然是CORS,背背这些理论点确定不为过吧,我就用三幅图对这个理论进行一些简单的总结

1.1 请求类型

1.1.1 简单请求

1.1.2 非简单请求

1.2 请求如何带上Cookie信息

2、实验

为实验作好前期准备工做,包含一个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 实验二

实验目的java

  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 字段,在看看响应内容,确实有消息返回了,内容以下:
ios

  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的值是否相等来肯定是否容许跨域访问的。经过该实验达到了咱们实验的目的。express

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 实验四

实验目的npm

  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请求,上述打印内容验证了实验目的中的一和二。json

  1. 下面继续深刻思考,来看看预检请求的请求头和响应头
请求头内容

响应头内容

上述Access-Control-Request-Headers与Access-Control-Allow-Headers同样,并且内容也正常返回了(步骤二中已经进行了展现),可是这不足以证实实验目的三,下面咱们认为增长一条头信息再来看结果。axios

  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.关注公众号执鸢者,领取学习资料,按期为你推送原创深度好文

image

image.png

相关文章
相关标签/搜索