閱讀目錄:
深入跨域問題(1) - 初識 CORS 跨域資源共享(本篇)
跨域問題寺董,一直困擾我們非常久,特別是在前后端分離開發(fā)條件下,幾乎一定會遇到跨域問題。
跨域也有很多解決方案:JSONP,iframe,代理,反向代理等坟乾。
如果是與后臺一起開發(fā)過的小伙伴,肯定對這一句感到熟悉:
Access-Control-Allow-Origin: *
其實蝶防,這就已經(jīng)屬于 CORS 跨域資源共享的內(nèi)容了甚侣,但是,前端和后臺交互的時候仍然存在很多很多問題间学。
這些問題的主要原因:你和后臺并不熟悉 CORS 殷费,不僅后端需要了解 CORS ,前端也要非常熟悉 5秃O晗邸!
在這篇文章里面嘿悬,我主要闡述 CORS 跨域資源共享实柠,在后續(xù)文章中,我會采用 node 模擬出跨域并解決善涨。
產(chǎn)生跨域的條件
瀏覽器安全的基石是 同源策略窒盐,什么是同源策略呢茶行?言簡意賅,就是三個相同:
- 協(xié)議相同登钥。
- 域名相同。
- 端口相同娶靡。
這三者相同的情況下牧牢,才被稱作 “同源”,同源策略姿锭,可以保證你的服務器的接口是隱私的塔鳍。
CORS 跨域資源共享就是指,在這個三者 一個或者多個不同 的情況下呻此,允許 跨源 獲取服務器接口的內(nèi)容轮纫。
但是,既然要突破 同源策略 焚鲜,那么 CORS 必須遵守一定 規(guī)則 來保證服務器的數(shù)據(jù)安全掌唾。
跨域的例子:
端口不同:
假設,你的電腦現(xiàn)在有開啟了兩個服務器忿磅,分別在 不同的端口 :
http://localhost:8080/index.html // 發(fā)送 ajax 請求
http://localhost:3000 // 提供接口
在這里糯彬,這個服務器并沒有遵守 同源策略 了,此時葱她,就產(chǎn)生了跨域問題撩扒。
協(xié)議不同:
舉一個很常見的例子,雙擊打開一個 html 文件吨些,你會看到瀏覽器上你會看到:
file:///Users/xxx/Documents/index.html // 客戶端
http://localhost:3000 // 服務器
這就是簡單的 協(xié)議不同 的跨域例子搓谆,這個例子,也是我們最好實現(xiàn)的例子 豪墅。泉手。。
域名不同:
這個更明顯了:
https://www.xxx.com/index.html // 客戶端
https://www.yyy.com // 服務器
這個例子偶器,我想不用過多解釋了吧螃诅。
CORS 資源共享
我想,大多數(shù)人在看 MDN 文檔上面的解釋時状囱,也會一臉懵逼吧术裸,感覺很有道理的樣子但不知道該怎么用。
說白了亭枷,CORS 只是在 HTTP 協(xié)議內(nèi)部袭艺,新增了若干個 首部字段 ,來制定 跨域資源共享 的實現(xiàn) 規(guī)則 叨粘。
這些首部字段猾编,有哪些呢瘤睹??答倡? HTTP訪問控制(CORS) MDN 文檔 轰传。
預請求
此規(guī)則規(guī)定,處于跨域環(huán)境并在下面幾個條件下瘪撇,瀏覽器會發(fā)送兩個請求給服務器获茬;
舉例說明:假設客戶端需要發(fā)起 PUT 請求
- 首先,客戶端要發(fā)送 OPTIONS 請求 給服務器倔既。
- 在 服務器內(nèi)部恕曲,需要對 OPTIONS 請求 ,做出一些 設定 渤涌,告訴客戶端 是否允許訪問 佩谣。
- 客戶端確認服務器允許該方法,最終發(fā)送 PUT 請求实蓬;否則茸俭,拋出錯誤,服務器拒絕訪問此方法安皱。
這種設定保證了服務器的 安全性瓣履,服務器可控制客戶端訪問的內(nèi)容 !A防袖迎!
觸發(fā)預請求有三種情況:
- 使用了某些方法,比如說 PUT, DELETE 等腺晾。
- Fetch 規(guī)范規(guī)定了對 CORS安全的首部字段集合燕锥,人為設置會觸發(fā)預請求。
- Content-Type的值不是
text/plain
悯蝉,multipart/form-data
归形,application/x-www-form-urlencoded
由于篇幅原因,我并沒有完全列出鼻由,請查閱 HTTP訪問控制(CORS) MDN文檔暇榴。
非預請求:
此規(guī)則規(guī)定,在跨域產(chǎn)生的條件下蕉世,某些請求和方法蔼紧,不需要預請求,只發(fā)送一個請求就行了狠轻。
簡單的請求比如說:GET, POST, HEAD 這三個方法奸例。
思考題目:
現(xiàn)在,有一個場景向楼,我們需要用 ajax 發(fā)送一個請求查吊,請問是否能夠觸發(fā)預請求 ?
例子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 文檔 。
- 瀏覽器同源政策及其規(guī)避方法 阮一峰评也。
- 跨域資源共享 CORS 詳解 阮一峰炼杖。
十分感謝上述參考鏈接的作者,他們的文章是十分有深度和值得多多研讀的仇参。