理論與實踐相結合完全理解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

相關文章
相關標籤/搜索