問答
1.什么是同源策略
①源(orgin)的定義
-
以百度為例晓避,輸入localtion.origin就可以得到源
-
源包括協(xié)議交排,域名也切,端口號扑媚。如
https://www.baidu.com/
,它的協(xié)議是https;域名為www.baidu,com;默認(rèn)的端口為443,所以可以省略雷恃,類似的還有http協(xié)議的默認(rèn)端口為80;ftp(文本傳輸協(xié)議)的默認(rèn)端口為21
②同源策略
- 同源策略是瀏覽器的一個功能疆股,如果瀏覽器有bug就有可能不支持。
- 同源是指
域名倒槐,協(xié)議旬痹,端口相同
,比如http://jirengu.com/a/b.js
和http://jirengu.com/index.php
(同源) - 同源策略的意思是只有同源的客戶端腳本比如js讨越,才可以讀寫對方的資源两残;
不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對方的資源把跨。比如a.com下的js不能讀取b.com下的資源 -
不同源的例子:
http://jirengu.com/main.js
和https://jirengu.com/a.php
(協(xié)議不同)
http://jirengu.com/main.js
和http://bbs.jirengu.com/a.php
(域名不同人弓,域名必須完全相同才可以)
http://jiengu.com/main.js
和http://jirengu.com:8080/a.php
(端口不同,第一個是80)
③注意
- 對于當(dāng)前頁面來說頁面存放的
JS 文件的域
不重要,重要的是加載該 JS 頁面所在什么域着逐。比如<script>標(biāo)簽引用了來源于不同地方http://www.artech.com
和http://www.jinnan.me/
的兩個JavaScript腳本票从,它們均與當(dāng)前頁面同源
1: <script src="http://www.artech.com/scripts/common.js"></script>
2: <script src="http://www.jinnan.me/scripts/utility.js"></script>
除了<script>標(biāo)簽,HTML還具有其它一些具有src屬性的標(biāo)簽,比如
<img>
滨嘱、<iframe>
和<link>
等,它們均具有跨域加載資源的能力浸间,所以同源策略對它們不做限制太雨。
對于這些具有src屬性的HTML標(biāo)簽來說,標(biāo)簽的每次加載都意味著針對目標(biāo)地址的一次HTTP-GET請求魁蒜。同源策略以及跨域資源共享在大部分情況下針對的是Ajax請求囊扳。同源策略主要限制了通過XMLHttpRequest實(shí)現(xiàn)的Ajax請求,如果請求的是一個“異源”地址兜看,瀏覽器將不允許讀取返回的內(nèi)容
2.什么是跨域锥咸?跨域有幾種實(shí)現(xiàn)形式
①跨域:只要協(xié)議、域名细移、端口有任何一個不同搏予,都被當(dāng)作是不同的域。為了突破同源策略的限制弧轧,跨域是指從一個網(wǎng)頁去請求另一個不同域的網(wǎng)頁的資源雪侥。
②跨域?qū)崿F(xiàn)形式:
1.降域:
對于主域相同而子域不同的例子碗殷,通過設(shè)置document.domain和iframe。
比如:可以在http://child1.a.com/a.html
和http://child2.a.com/b.html
兩個文件中分別加上document.domain = ‘a(chǎn).com’速缨;然后通過a.html文件中創(chuàng)建一個iframe锌妻,去控制iframe的contentDocument,這樣兩個js文件之間就可以“交互”了.
2.jsonp(json with padding)
由于直接用 XMLHttpRequest 請求不同域上的數(shù)據(jù)是不可以的旬牲。這種方式主要是通過動態(tài)插入一個 script 標(biāo)簽仿粹。瀏覽器對 script 的資源引用沒有同源限制,同時資源加載到頁面后會立即執(zhí)行(沒有阻塞的情況下) 原茅。但只支持get請求吭历,安全性不高
3.CORS(Cross-Origin Resource Sharing):
CORS 全稱是跨域資源共享(Cross-Origin Resource Sharing),是一種 ajax 跨域請求資源的方式员咽,支持現(xiàn)代瀏覽器毒涧,IE支持10以上。
實(shí)現(xiàn)方式很簡單贝室,當(dāng)你使用 XMLHttpRequest 發(fā)送請求時契讲,瀏覽器發(fā)現(xiàn)該請求不符合同源策略,會給該請求加一個請求頭: Origin 滑频,后臺進(jìn)行一系列處理捡偏,如果確定接受請求則在返回結(jié)果中加入一個響應(yīng)頭: Access-Control-Allow-Origin ; 瀏覽器判斷該相應(yīng)頭中是否包含 Origin 的值,如果有則瀏覽器會處理響應(yīng)峡迷,我們就可以拿到響應(yīng)數(shù)據(jù)银伟,如果不包含瀏覽器直接駁回,這時我們無法拿到響應(yīng)數(shù)據(jù)绘搞。
4.HTML5 postMessage
即跨文檔消息傳輸彤避,通過postMessage方法指明需要傳遞的數(shù)據(jù),以及目標(biāo)域名夯辖,接收端添加事件監(jiān)聽message琉预,通過事件的origin屬性判斷發(fā)送請求的域名,符合要求就接收數(shù)據(jù)蒿褂,客戶端的方法和服務(wù)端的監(jiān)聽必須配套使用圆米。
**5.其他Hack(利用hash、利用window.name) **
利用iframe和location.hash和window.name實(shí)現(xiàn)的跨域數(shù)據(jù)傳輸?shù)?br>
同源策略&跨域請求
JavaScript跨域總結(jié)與解決辦法
3.jsonp 的原理是什么
原理是利用script標(biāo)簽的可跨域性啄栓,在網(wǎng)頁中動態(tài)的創(chuàng)建并添加script標(biāo)簽娄帖,然后在請求頁面的url上添加一個callback函數(shù)名作為參數(shù)。后臺服務(wù)器將數(shù)據(jù)放在一個指定名字的callback函數(shù)給傳回來昙楚,由于網(wǎng)頁已經(jīng)定義的callback函數(shù)近速,參數(shù)被返回后,便會立即執(zhí)行。
4.CORS是什么
- CORS需要瀏覽器和服務(wù)器同時支持数焊。目前永淌,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10佩耳;
- 瀏覽器一旦發(fā)現(xiàn)AJAX請求跨源遂蛀,就會自動添加一些附加的頭信息——origin字段,告訴跨域的后臺這次跨域請求是由哪個源發(fā)出的
- 實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器干厚。只要服務(wù)器實(shí)現(xiàn)了CORS接口李滴,就可以跨源通信。服務(wù)器根據(jù)前端發(fā)過來的跨域的ajax請求的origin字段蛮瞄,決定是否同意這次的跨域訪問所坯;后臺可以通過設(shè)置一個標(biāo)頭決定是否通信
- 例如:假設(shè)我們現(xiàn)在需要從
http://www.test1.com
去http://www.test2.com
請求提取數(shù)據(jù),而JSONP只支持GET方法挂捅,這時候CORS就可以成為我們的選擇芹助。
利用CORS,http://www.test2.com
只需要添加一個標(biāo)頭,就可以允許來自http://www.test1.com
的請求闲先。在PHP中的header()設(shè)置:
header("Access-Control-Allow-Origin:*");
//*表示允許任何域向我們的服務(wù)端提交需求
header("Access-Control-Allow-Origin:http://www.test1.com")
//這樣就允許來自http://www.test1.com的需求了
代碼
1.本地搭建服務(wù)器状土,演示同源策略
本地搭建服務(wù)器(如果使用 SAE 可創(chuàng)建不同的代碼版本,這樣可通過1.xxx.sinapp.com
和2.xxx.sinapp.com
訪問了)伺糠。 修改 本地host蒙谓,通過不同域名訪問本地服務(wù)器。比如訪問http://a.com/index.html, http://b.com/ajax.php
训桶,本質(zhì)是 在 index.html 里使用 ajax 接口訪問 http://b.com/ajax.php
里的數(shù)據(jù)累驮,查看輸出報錯
1.第一步,找到hosts文件
2.第二部舵揭,打開hosts谤专。然后給本地默認(rèn)IP 127.0.0.1 綁定幾個域名,用于測試
4.第三步午绳,用a.com/origin.html下的ajax給b.com/origin.php發(fā)請求毒租,看跨域的時候數(shù)據(jù)能否從b.com發(fā)過來。
①origin.html代碼
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<div>a.com 頁面</div>
<script>
$.get('//b.com/origin.php',function(response){
console.log(response);
})
</script>
</body>
</html>
②origin.php代碼
<?php
echo 1234;
?>
③測試結(jié)果
2.至少使用一種方式解決跨域問題
1.jsonp方式
// a.com/origin.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<div>a.com 頁面</div>
<script>
function xxx(data){
alert(data);
};
var script=document.createElement('script');//添加動態(tài)腳本
script.src="http://b.com/origin.php?callback=xxx"; //此處callback的值箱叁,與上面xxx函數(shù)名要一致
document.body.appendChild(script);
</script>
</body>
</html>
// b.com/origin.php
<?php
$data=$_GET['callback'];
echo $data .'('. 123 .')';
?>
打印結(jié)果:
2.CORS的方式
// a.com/origin.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<div>a.com 頁面</div>
<script>
$.get('//b.com/origin.php',function(response){
alert(response);
})
</script>
</body>
</html>
// b.com/origin.php
//在origin.php文件內(nèi),設(shè)置標(biāo)頭惕医,以及要傳輸?shù)臄?shù)據(jù):
<?php
header("Access-Control-Allow-Origin:http://a.com");
echo '數(shù)據(jù)獲取成功';
?>
打印結(jié)果: