同源策略(協(xié)議+端口號+域名要相同)

1、jsonp跨域(只能解決get)
原理:動態(tài)創(chuàng)建一個script標簽。利用script標簽的src屬性不受同源策略限制,因為所有的src屬性和href屬性都不受同源策略的限制,可以請求第三方服務(wù)器資源內(nèi)容
步驟: 1).去創(chuàng)建一個script標簽
2).script的src屬性設(shè)置接口地址
3).接口參數(shù),必須要帶一個自定義函數(shù)名,要不然后臺無法返回數(shù)據(jù)
4).通過定義函數(shù)名去接受返回的數(shù)據(jù)

JSONP包含兩部分:回調(diào)函數(shù)和數(shù)據(jù)。?
回調(diào)函數(shù):當響應(yīng)到來時要放在當前頁面被調(diào)用的函數(shù)。?
數(shù)據(jù):就是傳入回調(diào)函數(shù)中的json數(shù)據(jù),也就是回調(diào)函數(shù)的參數(shù)了。
缺點:
#1)安全問題(請求代碼中可能存在安全隱患)
#2)要確定jsonp請求是否失敗并不容易
2、document.domain 基礎(chǔ)域名相同,子域名不同
瀏覽器同源策略限制:
#(1)不能通過ajax的方法去請求不同源中的文檔。
#(2)瀏覽器中不同域的框架之間是不能進行js的交互操作的。
? ? ? ?所以,在不同的框架之間(父子或同輩),是能夠獲取到彼此的window對象的,但不能使用獲取到的window對象的屬性和方法(html5中的postMessage方法是一個例外),總之,可以當做是只能獲取到一個幾乎無用的window對象。
? ? ? ?例如,在一個頁面 http:// www.example.com/a.html 中,有一個iframe框架它的src是http:// example.com/b.html, 很顯然,這個頁面與它里面的iframe框架是不同域的,所以是無法通過在頁面中書寫js代碼來獲取iframe中的東西的。所以我們就要用到document.domain
在頁面http:// www.a.com/dir/a.html中設(shè)置document.domain
<iframe src = "http://script.a.com/dir/b.html" id="iframe" onload = "loLoad()"></iframe>
<script>
document.domain = "a.com";//設(shè)置成主域
function test(){
? ? var iframe = document.getElementById("iframe");
? ? var win = iframe.contentWindow;
? ? //在這里就可以操作b.html
}
</script>
注意,document.domain的設(shè)置是有限制的:
只能把document.domain設(shè)置成自身或更高一級的父域,且主域必須相同。
例如:a.b.c.com 中某個文檔的document.domain 可以設(shè)成a.b.c.com、b.c.com 、c.com中的任意一個。
3、window.name 利用在一個瀏覽器窗口內(nèi),載入所有的域名都是共享一個window.name
? ? ? ?window的name屬性特征:name 值在不同的頁面(甚至不同域名)加載后依舊存在,并且可以支持非常長的 name 值(2MB),即在一個窗口(window)的生命周期內(nèi),窗口載入的所有的頁面都是共享一個window.name的,每個頁面window.name都有讀寫的權(quán)限。
正是由于window的name屬性的特征,所以可以使用window.name來進行跨域。
舉例:
1)在一個a.html頁面中,有如下代碼:
<script>
? ? window.name = "哈哈,我是頁面a設(shè)置的值喲!";
? ? //設(shè)置window.name的值
? ? setTimeout(function(){
? ? ? ? window.location = 'b.html';
? ? },3000);//3秒后把一個新頁面載入當前window
</script>
2)再在b.html中讀取window.name的值:
<script>
? ? alert(window.name);//讀取window.name的值
<script>
3)a.html載入3秒后,會跳轉(zhuǎn)到b.html頁面中
注意:
#1.window.name的值只能是字符串的形式,這個字符串的大小最大能允許2M左右甚至更大的一個容量,具體取決于不同的瀏覽器。
接下來使用window.name進行跨域舉例
比如:有一個example.com/a.html頁面,需要通過a.html頁面里的js來獲取另一個位于不同域上的頁面cnblogs.com/data.html里的數(shù)據(jù)。
1)創(chuàng)建cnblogs.com/data.html代碼:
<script>
? ? function getData(){
? ? //iframe載入data.html頁面會執(zhí)行此函數(shù)
? ? ? ? var ifr = document.getElementById("iframe");
? ? ? ? ifr.onload = function(){
? ? ? ? //這個時候iframe和a.html已經(jīng)處于同一源,可以互相訪問
? ? ? ? ? ? var data = ifr.contentWindow.name;
//獲取iframe中的window.name,也就是data.html中給它設(shè)置的數(shù)據(jù)
? ? ? ? ? ? alert(data);
? ? ? ? }
? ? ? ? ifr.src = 'b.html';//這里的b.html為隨便一個頁面,只要與a.html同源就行,目的是讓a.html能夠訪問到iframe中的東西,否則訪問不到
? ? }
</script>
<iframe id = "iframe" src = "cnblogs.com/data.html" style = "display:none" onload = "getData()"></iframe>
2)創(chuàng)建example.com/a.html的代碼:
<script>
? ? function getData(){
? ? //iframe載入data.html頁面會執(zhí)行此函數(shù)
? ? ? ? var ifr = document.getElementById("iframe");
? ? ? ? ifr.onload = function(){
? ? ? ? //這個時候iframe和a.html已經(jīng)處于同一源,可以互相訪問
? ? ? ? ? ? var data = ifr.contentWindow.name;
//獲取iframe中的window.name,也就是data.html中給它設(shè)置的數(shù)據(jù)
? ? ? ? ? ? alert(data);
? ? ? ? }
? ? ? ? ifr.src = 'b.html';//這里的b.html為隨便一個頁面,只要與a.html同源就行,目的是讓a.html能夠訪問到iframe中的東西,否則訪問不到
? ? }
</script>
<iframe id = "iframe" src = "cnblogs.com/data.html" style = "display:none" onload = "getData()"></iframe>
想要即使a.html頁面不跳轉(zhuǎn)也能得到data.html里的數(shù)據(jù)。在a.html頁面中使用一個隱藏的iframe來充當一個中間人角色,由iframe去獲取data.html的數(shù)據(jù),然后a.html再去得到iframe獲取到的數(shù)據(jù)。
<script>
? ? function getData(){
? ? //iframe載入data.html頁面會執(zhí)行此函數(shù)
? ? ? ? var ifr = document.getElementById("iframe");
? ? ? ? ifr.onload = function(){
? ? ? ? //這個時候iframe和a.html已經(jīng)處于同一源,可以互相訪問
? ? ? ? ? ? var data = ifr.contentWindow.name;
//獲取iframe中的window.name,也就是data.html中給它設(shè)置的數(shù)據(jù)
? ? ? ? ? ? alert(data);
? ? ? ? }
? ? ? ? ifr.src = 'b.html';//這里的b.html為隨便一個頁面,只要與a.html同源就行,目的是讓a.html能夠訪問到iframe中的東西,否則訪問不到
? ? }
</script>
<iframe id = "iframe" src = "cnblogs.com/data.html" style = "display:none" onload = "getData()"></iframe>
4、使用跨域資源共享(CORS)來跨域
CORS:一種跨域訪問的機制,可以讓AJAX實現(xiàn)跨域訪問;CORS允許一個域上的網(wǎng)絡(luò)應(yīng)用向另一個域提交跨域AJAX請求。
原理:服務(wù)器設(shè)置Access-Control-Allow-Origin HTTP響應(yīng)頭之后,瀏覽器將會允許跨域請求.
就是使用自定義的HTTP頭部讓瀏覽器與服務(wù)器進行溝通,從而決定請求或響應(yīng)是應(yīng)該成功,還是應(yīng)該失敗。
1) IE中對CORS的實現(xiàn)是通過xdr
var xdr = new XDomainRequest();
xdr.onload = function(){
? ? console.log(xdr.responseText);
}
xdr.open('get', 'http://www.test.com');
......
xdr.send(null);
2) 其它瀏覽器中的實現(xiàn)就在xhr中
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
? if(xhr.readyState === 4 && xhr.status === 200){
? ? ? ? console.log(xhr.responseText);
? ? ? ? }
? ? }
}
xhr.open('get', 'http://www.test.com');
......
xhr.send(null);
3) 實現(xiàn)跨瀏覽器的CORS
function createCORS(method, url){
? ? var xhr = new XMLHttpRequest();
? ? if('withCredentials' in xhr){
? ? ? ? xhr.open(method, url, true);
? ? }else if(typeof XDomainRequest != 'undefined'){
? ? ? ? var xhr = new XDomainRequest();
? ? ? ? xhr.open(method, url);
? ? }else{
? ? ? ? xhr = null;
? ? }
? ? return xhr;
}
var request = createCORS('get', 'http://www.test.com');
if(request){
? ? request.onload = function(){
? ? ? ? ......
? ? };
? ? request.send();
}
5、利用h5新特性window.postMessage()
window.postMessage(message,targetOrigin) 方法是html5新引進的特性,可以使用它來向其它的window對象發(fā)送消息,無論這個window對象是屬于同源或不同源(可實現(xiàn)跨域),目前IE8+、FireFox、Chrome、Opera等瀏覽器都已經(jīng)支持window.postMessage方法。
message:為要發(fā)送的消息,類型只能為字符串;
targetOrigin:用來限定接收消息的那個window對象所在的域,如果不想限定域,可以使用通配符 “*”。
1)創(chuàng)建www.test.com/a.html頁面代碼:
<script>
function onLoad(){
? ? var iframe = document.getElementById("iframe");
? ? var win = iframe.contentWindow;
? ? win.postMessage('哈哈,我是來自頁面a.html的信息喲!','*');//向不同域的www.script.com/b.html發(fā)送消息
}
</script>
<iframe id="iframe" src="www.script.com/b.html" onload="onLoad()"></iframe>
2)創(chuàng)建www.script.com/b.html頁面代碼:
<script>
window.onmessage = function (e) {
e = e || event ;
alert (e.data);
}
</script>
優(yōu)點:使用postMessage來跨域傳送數(shù)據(jù)還是比較直觀和方便的;?
缺點:?IE6、IE7不支持,所以用不用還得根據(jù)實際需要來決定。