閱讀目錄
深入跨域問題(1) - 初識 CORS 跨域資源共享(本篇)
前言
跨域問題,一直困擾我們非常久,特別是在前後端分離開發條件下,幾乎一定會遇到跨域問題。
跨域也有很多解決方案:JSONP,iframe,代理,反向代理等。
如果是與後臺一起開發過的小夥伴,肯定對這一句感到熟悉:
Access-Control-Allow-Origin: *
複製程式碼
其實,這就已經屬於 CORS 跨域資源共享的內容了,但是,前端和後臺互動的時候仍然存在很多很多問題。
這些問題的主要原因:你和後臺並不熟悉 CORS ,不僅後端需要了解 CORS ,前端也要非常熟悉 !!!
在這篇文章裡面,我主要闡述 CORS 同源策略,在後續文章中,我會採用 node 模擬出跨域並解決。
產生跨域的條件
瀏覽器安全的基石是 同源策略,什麼是同源策略呢?言簡意賅,就是三個相同:
- 協議相同。
- 域名相同。
- 埠相同。
這三者相同的情況下,才被稱作 “同源”,同源策略,可以保證你的伺服器的介面是隱私的。
CORS 跨域資源共享就是指,在這個三者 一個或者多個不同 的情況下,允許 跨源 獲取伺服器介面的內容。
但是,既然要突破 同源策略 ,那麼 CORS 必須遵守一定 規則 來保證伺服器的資料安全。
跨域的例子:
埠不同:
假設,你的電腦現在有開啟了兩個伺服器,分別在 不同的埠 :
http://localhost:8080/index.html // 傳送 ajax 請求
http://localhost:3000 // 提供介面
複製程式碼
在這裡,這個伺服器並沒有遵守 同源策略 了,此時,就產生了跨域問題。
協議不同:
舉一個很常見的例子,雙擊開啟一個 html 檔案,你會看到瀏覽器上你會看到:
file:///Users/xxx/Documents/index.html // 客戶端
http://localhost:3000 // 伺服器
複製程式碼
這就是簡單的 協議不同 的跨域例子,這個例子,也是我們最好實現的例子 。。。
域名不同:
這個更明顯了:
https://www.xxx.com/index.html // 客戶端
https://www.yyy.com // 伺服器
複製程式碼
這個例子,我想不用過多解釋了吧。
CORS 資源共享
我想,大多數人在看 MDN 文件上面的解釋時,也會一臉懵逼吧,感覺很有道理的樣子但不知道該怎麼用。
說白了,CORS 只是在 HTTP 協議內部,新增了若干個 首部欄位 ,來制定 跨域資源共享 的實現 規則 。
這些首部欄位,有哪些呢??? HTTP訪問控制(CORS) MDN 文件 。
預請求
此規則規定,處於跨域環境並在下面幾個條件下,瀏覽器會傳送兩個請求給伺服器;
舉例說明:假設客戶端需要發起 PUT 請求
- 首先,客戶端要傳送 OPTIONS 請求 給伺服器。
- 在 伺服器內部,需要對 OPTIONS 請求 ,做出一些 設定 ,告訴客戶端 是否允許訪問 。
- 客戶端確認伺服器允許該方法,最終傳送 PUT 請求;否則,丟擲錯誤,伺服器拒絕訪問此方法。
這種設定保證了伺服器的 安全性,伺服器可控制客戶端訪問的內容 !!!
觸發預請求有三種情況:
- 使用了某些方法,比如說 PUT, DELETE 等。
- Fetch 規範規定了對 CORS安全的首部欄位集合,人為設定會觸發預請求。
- Content-Type的值不是
text/plain
,multipart/form-data
,application/x-www-form-urlencoded
由於篇幅原因,我並沒有完全列出,請查閱 HTTP訪問控制(CORS) MDN文件。
非預請求:
此規則規定,在跨域產生的條件下,某些請求和方法,不需要預請求,只傳送一個請求就行了。
簡單的請求比如說:GET, POST, HEAD 這三個方法。
思考題目:
現在,有一個場景,我們需要用 ajax 傳送一個請求,請問是否能夠觸發預請求 ?
例子1:
var data = { name: 'BruceLee', password: '123456' };
$.ajax({
url: "http://localhost:3000",
type: "get",
success: function (result) {
console.log(result);
},
error: function (msg) {
console.log(msg);
}
})
複製程式碼
例子2:
var data = { name: 'BruceLee', password: '123456' };
$.ajax({
url: "http://localhost:3000",
type: "post",
success: function (result) {
console.log(result);
},
error: function (msg) {
console.log(msg);
}
})
複製程式碼
例子3:
var data = { name: 'BruceLee', password: '123456' };
$.ajax({
url: "http://localhost:3000",
type: "post",
data: JSON.stringify(data),
contentType: 'application/json;charset=utf-8',
success: function (result) {
console.log(result);
},
error: function (msg) {
console.log(msg);
}
})
複製程式碼
仔細分析上述的三個例子,例子很簡單,作為前端的你,會對 CORS 擁有新的認知。
參考與鳴謝:
- HTTP訪問控制(CORS) MDN 文件 。
- 瀏覽器同源政策及其規避方法 阮一峰。
- 跨域資源共享 CORS 詳解 阮一峰。
十分感謝上述參考連結的作者,他們的文章是十分有深度和值得多多研讀的。