對于前端來說溪北,跨域是基礎(chǔ)工作之一。
同源策略
提到跨域夺脾,不得不先說同源策略之拨。
同源策略是一種指瀏覽器的安全機(jī)制,只允許與本域下的接口交互咧叭。不同源的客戶端腳本在沒有明確授權(quán)的情況下蚀乔,不能讀寫對方的資源。
本域是指:
- 同協(xié)議:都是http或者都是https
- 同域名: 如 http://test.com/a 和 http://test.com/b
- 同端口: 如都是3000端口
打個比方菲茬,淘寶域名的網(wǎng)站請求騰訊域名網(wǎng)站的資源吉挣,會失敗,相反婉弹,亦同(馬爸爸們怎么可能允許這種事情發(fā)生??)睬魂。
失敗镀赌?在哪失斅认?沒發(fā)出去商佛?發(fā)出去了人家服務(wù)器沒理你喉钢?還是理你了但是瀏覽器不給你看?
測一把良姆,測試中的服務(wù)器端沒有做任何域名校驗肠虽。代碼
結(jié)果是,代碼發(fā)出去了歇盼,服務(wù)器也響應(yīng)并返回了舔痕,瀏覽器中 NetWorks 請求的 Status Code也是200评抚,但是無法看到響應(yīng)體豹缀。
因而,是瀏覽器認(rèn)為不安全慨代,從而屏蔽了響應(yīng)體邢笙。
跨域
再說跨域,那就是允許不同域的接口進(jìn)行交互侍匙,就是POST氮惯、GET的url不是當(dāng)前的網(wǎng)站叮雳,域名不同。(比如一個馬爸爸在某些特殊情況下竟然允許另外一個馬爸爸請求自己的資源??妇汗。帘不。。)
跨域有幾種方式:
- JSONP
- CORS
- 降域
- postMessage
JSONP
- 無論是靜態(tài)頁面杨箭、動態(tài)頁面寞焙、還是web服務(wù)、WCR互婿, ajax直接請求普通文件都存在跨域問題捣郊;
- 頁面中調(diào)用 js 文件不受跨域的影響(凡是擁有 src 屬性的標(biāo)簽都有跨域能力, e.g. img iframe );
- 那么慈参,如果在遠(yuǎn)程服務(wù)器上設(shè)法把數(shù)據(jù)裝進(jìn) js 格式的文件里呛牲,供客戶端調(diào)用和進(jìn)一步處理, 就可以通過web端跨域訪問到這份數(shù)據(jù)驮配;
- js 支持 JSON娘扩,在加載src文件時,會作為 js 來執(zhí)行僧凤;
綜上畜侦,在請求數(shù)據(jù)時,請求帶一個 callback 參數(shù)躯保,參數(shù)值為處理返回數(shù)據(jù)的函數(shù)的函數(shù)名旋膳,服務(wù)器動態(tài)生成JSON數(shù)據(jù),將這個 callback 所帶的函數(shù)名包裹住 JSON 數(shù)據(jù)途事,然后返回验懊, 客戶端加載則立即執(zhí)行該 callback funciton, 從而對數(shù)據(jù)進(jìn)行相應(yīng)的處理。
這種非正式傳輸協(xié)議尸变,就稱作 JSONP (JSON with Padding) , 可以讓網(wǎng)頁從別的域名獲取數(shù)據(jù)义图,并將 JSON 數(shù)據(jù)填充進(jìn) callback function 從而回調(diào)。
JSONP 步驟
- 定義 callback函數(shù) cb;
- 創(chuàng)建script標(biāo)簽召烂,src的地址為請求的url碱工,最后增加參數(shù) callback=cb;
- 服務(wù)端在收到請求后,解析參數(shù)奏夫,計算并生成 JSON 數(shù)據(jù)怕篷,輸出 cb(JSON) 字符串;
- 客戶端收到數(shù)據(jù), 作為 js 執(zhí)行酗昼,調(diào)用 cb 函數(shù)廊谓,服務(wù)器返回的 JSON 為 cb 的參數(shù)。
JSONP 實例
CORS
CORS 是指跨域資源共享(Cross-Origin Resource Sharing)麻削,是?種 ajax 跨域請求資源的?式蒸痹,?持現(xiàn)代瀏覽器(IE 10+)春弥。
CORS步驟:
- 使?XMLHttpRequest 發(fā)送請求時,發(fā)現(xiàn)該請求不符合同源策略叠荠,給該請求加?個 Origin請求頭;
- 后臺對請求的域名進(jìn)行判斷匿沛,在返回結(jié)果中加入相應(yīng)的響應(yīng)頭 Access-Control-Allow-Origin;
- 瀏覽器判斷該響應(yīng)頭中是否包含 Origin 的值,如果包含則不屏蔽響應(yīng)體榛鼎,文件繼續(xù)執(zhí)行俺祠,反之則屏蔽響應(yīng)體,該報錯報錯借帘,該跳過跳過蜘渣。
CORS 實例
核心部分
res.header("Access-Control-Allow-Origin", "http://www.aaa.com:8080");
res.header("Access-Control-Allow-Origin", "*"); // accept all the domains
降域
對于主域相同但是子域不相同的一種解決方法。
降域步驟
- 比如兩個域名分別是 a.test.com/a.html 以及 b.test.com/b.html;
- 在兩個文件中分別加上 document.domain = "test.com";
- 在 a.html 中創(chuàng)建一個iframe肺然,src 為 b.html , 控制其content Document蔫缸,從而兩個 js 文件就可以"交互"了。
降域 實例
postMessage
通常用于:
- 頁面和其打開的新窗口的數(shù)據(jù)傳遞
- 多窗口之間數(shù)據(jù)傳遞
- 頁面與其 iframe 數(shù)據(jù)傳遞
postMessage(data,origin) 方法接受兩個參數(shù):
- data: 要傳遞的數(shù)據(jù)际起,html5規(guī)范中提到該參數(shù)可以是JavaScript的任意基本類型或可復(fù)制的對象拾碌,然而并不是所有瀏覽器都做到了這點兒,部分瀏覽器只能處理字符串參數(shù)街望,所以我們在傳遞參數(shù)的時候需要使用JSON.stringify()方法對對象參數(shù)序列化校翔,在低版本IE中引用json2.js可以實現(xiàn)類似效果。
- origin: 字符串灾前,指明目標(biāo)窗口的源防症,協(xié)議+主機(jī)+端口號[+URL],URL會被忽略哎甲,所以可以不寫蔫敲,這個參數(shù)是為了安全考慮,postMessage()方法只會將message傳遞給指定窗口炭玫,當(dāng)然如果愿意也可以建參數(shù)設(shè)置為"*"奈嘿,這樣可以傳遞給任意窗口,如果要指定和當(dāng)前窗口同源的話設(shè)置為"/"吞加。
window.postMessage() 方法被調(diào)用時裙犹,會在所有頁面腳本執(zhí)行完畢之后向目標(biāo)窗口派發(fā)一個 MessageEvent.
postMessage 實例
核心部分
// a.test.html
const input = document.querySelector('input')
input.addEventListener('input', function () {
window.frames[0].postMessage(this.value, '*')
})
// 監(jiān)聽其它頁面發(fā)送來的消息
window.addEventListener('message', function (e) {
input.value = e.data;
});
// b.test.html
const input = document.querySelector('input')
input.addEventListener('input', function () {
window.parent.postMessage(this.value, '*')
})
// 監(jiān)聽其它頁面發(fā)送來的消息
window.addEventListener('message', function (e) {
input.value = e.data;
});
降域和postMessage嘛,我個人感覺是沒有另外兩種使用廣泛衔憨,JSONP叶圃、CORS都是實打?qū)嵉男枰蠖伺浜系模欢绻蠖送圾B你巫财,那...
綜上所述盗似,后端同樣是前端的必備技能啊哩陕,666.....