什么是同源策略
同源策略 (Same-Origin Policy) 最早由 Netscape 公司提出, 所謂同源就是要求, 域名, 協(xié)議, 端口相同吮龄。非同源的腳本不能訪問或者操作其他域的頁面對(duì)象(如DOM等)失息。作為著名的安全策略, 雖然它只是一個(gè)規(guī)范, 并不強(qiáng)制要求, 但現(xiàn)在所有支持 javaScript 的瀏覽器都會(huì)使用這個(gè)策略忿峻。 以至于該策略成為瀏覽器最核心最基本的安全功能, 如果缺少了同源策略, web的安全將無從談起。
同源策略要求三同, 即: 同域, 同協(xié)議, 同端口。
同域即host相同, 頂級(jí)域名, 一級(jí)域名, 二級(jí)域名, 三級(jí)域名等必須相同, 且域名不能與 ip 對(duì)應(yīng);
同協(xié)議要求, http與https協(xié)議必須保持一致;
同端口要求, 端口號(hào)必須相同。
什么是跨域靡砌?跨域有幾種實(shí)現(xiàn)形式
只要協(xié)議、域名声邦、端口有任何一個(gè)不同乏奥,都被當(dāng)作是不同的域,跨域就是訪問非本域的資源亥曹。
跨域?qū)崿F(xiàn)方式
1邓了、JSONP
2、CORS
3媳瞪、降域
4骗炉、PostMessage
JSONP 的原理是什么
JSONP是服務(wù)器與客戶端跨源通信的常用方法。最大特點(diǎn)就是簡(jiǎn)單適用蛇受,老式瀏覽器全部支持句葵,服務(wù)器改造非常小。它的基本思想是,AJAX 無法跨域是受到“同源政策”的限制乍丈,但是帶有src屬性的標(biāo)簽(例如<script>剂碴、<img>、<iframe>)是不受該政策限制的轻专,因此通過向頁面中動(dòng)態(tài)添加標(biāo)簽來完成對(duì)跨域資源的訪問忆矛,這也是 JSONP 方案最核心的原理。
通常我們使用都是引用的靜態(tài)資源(主要是 js 文件)请垛,其實(shí)它也可以用來引用動(dòng)態(tài)資源(php催训、jsp、aspx等)宗收,后臺(tái)服務(wù)被訪問后返回一個(gè)“JavaScript函數(shù)調(diào)用”形式的字符串漫拭,由于是字符串,因此在后臺(tái)的時(shí)候不會(huì)起到任何作用混稽,但到了前臺(tái)采驻,放入標(biāo)簽之內(nèi),就成了一個(gè)合法的 JavaScript 函數(shù)調(diào)用荚坞,實(shí)參是我們真正需要的數(shù)據(jù)挑宠,被調(diào)用的回調(diào)函數(shù)也已經(jīng)實(shí)現(xiàn)了,因此就會(huì)順利的被調(diào)用颓影。
JSONP 最大的優(yōu)點(diǎn)就是兼容性非常好,其原理決定了即便在非常古老的瀏覽器上也能夠很好的被實(shí)現(xiàn)懒鉴。
JSONP 的主要缺點(diǎn)有兩個(gè)诡挂,一是只能 GET 不能 POST,因?yàn)槭峭ㄟ^引用的資源临谱,參數(shù)全都顯式的放在URL里璃俗,和 AJAX 沒有關(guān)系。二是存在安全隱患悉默,動(dòng)態(tài)插入標(biāo)簽其實(shí)就是一種腳本注入城豁,會(huì)受到跨站腳本攻擊。
CORS是什么
CORS是一個(gè)W3C標(biāo)準(zhǔn)抄课,全稱是"跨域資源共享"(Cross-origin resource sharing)唱星。CORS需要瀏覽器和服務(wù)器同時(shí)支持。目前跟磨,所有瀏覽器都支持該功能间聊,IE瀏覽器不能低于IE10。它允許瀏覽器向跨源服務(wù)器抵拘,發(fā)出XMLHttpRequest請(qǐng)求哎榴,從而克服了AJAX只能同源使用的限制。
瀏覽器將CORS請(qǐng)求分成兩類:簡(jiǎn)單請(qǐng)求(simple request)和非簡(jiǎn)單請(qǐng)求(not-so-simple request)。
簡(jiǎn)單請(qǐng)求:瀏覽器直接發(fā)出CORS請(qǐng)求尚蝌。具體來說迎变,就是在頭信息之中,增加一個(gè)Origin
字段飘言。
非簡(jiǎn)單請(qǐng)求:是對(duì)服務(wù)器有特殊要求的請(qǐng)求衣形,比如請(qǐng)求方法是PUT
或DELETE
,或者Content-Type
字段的類型是application/json
热凹。
跨域的解決方式
JSONP
JSONP是服務(wù)器與客戶端跨源通信的常用方法泵喘。利用script標(biāo)簽可以引入其它域的JS這一特性,來實(shí)現(xiàn)跨域訪問接口般妙。JSONP最大特點(diǎn)就是簡(jiǎn)單適用纪铺,老式瀏覽器全部支持,服務(wù)器改造非常小碟渺。但前提是后端支持鲜锚。
1、動(dòng)態(tài)添加<script>
元素苫拍,向服務(wù)器發(fā)出請(qǐng)求
var change = document.querySelector('.change')
var newsList = document.querySelector('.news-list')
change.addEventListener('click', function(){
var script = document.createElement('script');
script.src= 'http://localhost:8080/getNews?callback=appendHtml'
document.head.appendChild(script);
document.head.removeChild(script);
})
2芜繁、用src 中 callback
參數(shù) 指定回調(diào)函數(shù)的名字
function appendHtml(news){
var html = '';
for( var i=0; i<news.length; i++){
html += '<li>' + news[i] + '</li>';
}
newsList.innerHTML = html;
}
})
3、服務(wù)器收到這個(gè)請(qǐng)求以后绒极,會(huì)將數(shù)據(jù)會(huì)放在回調(diào)函數(shù)的參數(shù)位置返回骏令。
app.get('/getNews', function(req, res){
var news = [
"第11日前瞻:中國(guó)沖擊4金 博爾特再戰(zhàn)200米羽球",
"正直播柴飚/洪煒出戰(zhàn) 男雙力爭(zhēng)會(huì)師決賽",
"女排將死磕巴西!郎平安排男陪練模仿對(duì)方核心",
"沒有中國(guó)選手和巨星的110米欄 我們還看嗎垄提?",
"中英上演奧運(yùn)金牌大戰(zhàn)",
"博彩賠率挺中國(guó)奪回第二紐約時(shí)報(bào):中國(guó)因?qū)κ址幎鴣G失的獎(jiǎng)牌最多",
"最“出柜”奧運(yùn)榔袋?同性之愛閃耀里約",
"下跪拜謝與洪荒之力一樣 都是真情流露"
]
var data = [];
for(var i=0; i<3; i++){
var index = parseInt(Math.random()*news.length);
data.push(news[index]);
news.splice(index, 1);
}
var callback = req.query.callback;
if(callback){
res.send(callback + '('+ JSON.stringify(data) + ')');
}else{
res.send(data);
}
})
JSONP的優(yōu)點(diǎn)是:它不像XMLHttpRequest
對(duì)象實(shí)現(xiàn)的Ajax請(qǐng)求那樣受到同源策略的限制;它的兼容性更好铡俐,在更加古老的瀏覽器中都可以運(yùn)行凰兑,不需要XMLHttpRequest或ActiveX的支持;并且在請(qǐng)求完畢后可以通過調(diào)用callback的方式回傳結(jié)果审丘。
JSONP的缺點(diǎn)則是:它只支持GET請(qǐng)求而不支持POST等其它類型的HTTP請(qǐng)求吏够;它只支持跨域HTTP請(qǐng)求這種情況,不能解決不同域的兩個(gè)頁面之間如何進(jìn)行JavaScript
調(diào)用的問題滩报。
CORS
CORS(Cross-Origin Resource Sharing)
跨域資源共享锅知,定義了必須在訪問跨域資源時(shí),瀏覽器與服務(wù)器應(yīng)該如何溝通露泊。CORS
背后的基本思想就是使用自定義的HTTP頭部讓瀏覽器與服務(wù)器進(jìn)行溝通喉镰,從而決定請(qǐng)求或響應(yīng)是應(yīng)該成功還是失敗。在服務(wù)器中設(shè)置響應(yīng)頭字段即可:
res.header("Access-Control-Allow-Origin","url")
CORS與JSONP的使用目的相同惭笑,但是比JSONP更強(qiáng)大侣姆。
JSONP只支持GET
請(qǐng)求生真,CORS支持所有類型的HTTP請(qǐng)求。JSONP的優(yōu)勢(shì)在于支持老式瀏覽器捺宗,以及可以向不支持CORS的網(wǎng)站請(qǐng)求數(shù)據(jù)柱蟀。
postMessage
postMessage() 方法允許來自不同源的腳本采用異步方式進(jìn)行有限的通信,可以實(shí)現(xiàn)跨文本檔蚜厉、多窗口长已、跨域消息傳遞。第二個(gè)參數(shù)可以是*
但如果你設(shè)置了一個(gè)URL但不相符昼牛,那么該事件不會(huì)被分發(fā)术瓮。
父頁面發(fā)送消息:
window.frames[0].postMessage('message', origin)
iframe接受消息:
window.addEventListener('message',function(e){
if(e.source!=window.parent) return;//若消息源不是父頁面則退出
//TODO ...
});
其中 e 對(duì)象有三個(gè)重要的屬性
- data, 表示父頁面?zhèn)鬟f過來的message
- source, 表示發(fā)送消息的窗口對(duì)象
- origin, 表示發(fā)送消息窗口的源(協(xié)議+主機(jī)+端口號(hào))