瀏覽器安全的基石是"同源政策"该镣。所謂"同源"指的是"三個相同"。
- 協(xié)議相同
- 域名相同
- 端口相同
同源政策的目的响谓,是為了保證用戶信息的安全损合,防止惡意的網站竊取數據省艳。雖然這些限制是必要的,但是有時很不方便嫁审,合理的用途也受到影響跋炕。所以引出跨域的幾種解決方式。如有錯誤請指正律适。
首先對于ajax的請求不能發(fā)送:
- JSONP
- CROS
- JSONP
JSONP是服務器與客戶端跨源通信的常用方法辐烂。最大特點就是簡單適用,老式瀏覽器全部支持捂贿,服務器改造非常小纠修。
它的基本思想是,網頁通過添加一個<script>
元素厂僧,向服務器請求JSON數據扣草,這種做法不受同源政策限制;服務器收到請求后颜屠,將數據放在一個指定名字的回調函數里傳回來辰妙。
$('.change').addEventListener('click', function(){
var script = document.createElement('script');
script.src = 'http://127.0.0.1:8080/getNews?callback=appendHtml';
//向服務器http://127.0.0.1:8080發(fā)送請求,請求的查詢字符串有一個callback參數甫窟,用來指定回調函數的名字
document.head.appendChild(script);
//服務器收到請求后密浑,將數據放在回調函數的參數位置返回
document.head.removeChild(script);
})
function appendHtml(news){
var html = '';
for( var i=0; i<news.length; i++){
html += '<li>' + news[i] + '</li>';
}
console.log(html);
$('.news').innerHTML = html;
}
function $(id){
return document.querySelector(id);
}
上面代碼通過動態(tài)添加<script>
元素,向服務器http://127.0.0.1:8080發(fā)出請求蕴坪。注意肴掷,該請求的查詢字符串有一個callback
參數,用來指定回調函數的名字背传,這對于JSONP是必需的呆瞻。
由于<script>
元素請求的腳本,直接作為代碼運行径玖。這時痴脾,只要瀏覽器定義了appendHtml函數,該函數就會立即調用梳星。作為參數的JSON數據被視為JavaScript對象赞赖,而不是字符串,因此避免了使用JSON.parse
的步驟冤灾。
服務器收到請求后前域,將數據傳給回調函數返回
app.get('/getNews', function(req, res){
var news = [
"第11日前瞻:中國沖擊4金 博爾特再戰(zhàn)200米羽球",
"正直播柴飚/洪煒出戰(zhàn) 男雙力爭會師決賽",
"女排將死磕巴西!郎平安排男陪練模仿對方核心",
"沒有中國選手和巨星的110米欄 我們還看嗎韵吨?",
"中英上演奧運金牌大戰(zhà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 cb = req.query.callback;
if(cb){
res.send(cb + '('+ JSON.stringify(data) + ')');
}else{
res.send(data);
}
})
- CORS
CORS
是跨源資源分享(Cross-Origin Resource Sharing)的縮寫。它是W3C標準,是跨源AJAX請求的根本解決方法椿疗。相比JSONP只能發(fā)GET
請求漏峰,CORS允許任何類型的請求。CORS需要瀏覽器和服務器同時支持届榄。目前浅乔,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10铝条。
瀏覽器將CORS請求分成兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)靖苇。
只要同時滿足以下兩大條件,就屬于簡單請求攻晒。
(1) 請求方法是以下三種方法之一:
- HEAD
- GET
- POST
(2)HTTP的頭信息不超出以下幾種字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三個值application/x-www-form-urlencoded顾复、multipart/form-data、text/plain
凡是不同時滿足上面兩個條件鲁捏,就屬于非簡單請求芯砸。
瀏覽器對這兩種請求的處理,是不一樣的给梅。
- 簡單請求
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://b.hth:8080/getNews', true);
xhr.send();
//xhr.open的傳的url為絕對路徑假丧,也就是你要跨域訪問的接口地址
服務器端:
res.header("Access-Control-Allow-Origin", "http://a.hth:8080");
//指定可以請求數據的域名為http://a.hth:8080
- 非簡單請求
非簡單請求是那種對服務器有特殊要求的請求,比如請求方法是PUT
或DELETE
动羽,或者Content-Type
字段的類型是application/json
包帚。
非簡單請求的CORS請求,會在正式通信之前运吓,增加一次HTTP查詢請求渴邦,稱為"預檢"請求(preflight)。
瀏覽器先詢問服務器拘哨,當前網頁所在的域名是否在服務器的許可名單之中谋梭,以及可以使用哪些HTTP動詞和頭信息字段。只有得到肯定答復倦青,瀏覽器才會發(fā)出正式的XMLHttpRequest
請求瓮床,否則就報錯。
var url = 'http://api.alice.com/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();
上面代碼中产镐,HTTP請求的方法是PUT
隘庄,并且發(fā)送一個自定義頭信息X-Custom-Header
。
下面設置請求回應設置http的頭部Access-Control-Allow-Origin
為*
,表示同意任意跨源請求癣亚。
res.header("Access-Control-Allow-Origin", "*");
iframe
如果兩個網頁不同源丑掺,就無法拿到對方的DOM。典型的例子是iframe
窗口和window.open
方法打開的窗口述雾,它們與父窗口無法通信吼鱼。
- 降域:
如果兩個窗口一級域名相同蓬豁,只是二級域名不同,那么設置上一節(jié)介紹的document.domain
屬性菇肃,就可以規(guī)避同源政策,拿到DOM取募。 - window.postMessage
HTML5為了解決這個問題琐谤,引入了一個全新的API:跨文檔通信 API
window.frames[0].postMessage(this.value,'*');//發(fā)送消息
window.parent.postMessage(this.value, '*');
參考鏈接:
- 跨域資源共享 CORS 詳解(阮一峰)
- 詳解js跨域問題
- [瀏覽器同源政策及其規(guī)避方法](http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
4010870-78d3af658d991db4.png
)