問答
1.什么是同源策略
①源(orgin)的定義
-
以百度為例,輸入localtion.origin就可以得到源
Paste_Image.png -
源包括協(xié)議,域名,端口號(hào)。如
https://www.baidu.com/
,它的協(xié)議是https;域名為www.baidu,com;默認(rèn)的端口為443,所以可以省略,類似的還有http協(xié)議的默認(rèn)端口為80;ftp(文本傳輸協(xié)議)的默認(rèn)端口為21
②同源策略
- 同源策略是瀏覽器的一個(gè)功能,如果瀏覽器有bug就有可能不支持。
- 同源是指
域名,協(xié)議,端口相同
,比如http://jirengu.com/a/b.js
和http://jirengu.com/index.php
(同源) - 同源策略的意思是只有同源的客戶端腳本比如js,才可以讀寫對(duì)方的資源;
不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對(duì)方的資源。比如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
(端口不同,第一個(gè)是80)
③注意
- 對(duì)于當(dāng)前頁(yè)面來說頁(yè)面存放的
JS 文件的域
不重要,重要的是加載該 JS 頁(yè)面所在什么域。比如<script>標(biāo)簽引用了來源于不同地方http://www.artech.com
和http://www.jinnan.me/
的兩個(gè)JavaScript腳本,它們均與當(dāng)前頁(yè)面同源
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>
等,它們均具有跨域加載資源的能力,所以同源策略對(duì)它們不做限制。
對(duì)于這些具有src屬性的HTML標(biāo)簽來說,標(biāo)簽的每次加載都意味著針對(duì)目標(biāo)地址的一次HTTP-GET請(qǐng)求。同源策略以及跨域資源共享在大部分情況下針對(duì)的是Ajax請(qǐng)求。同源策略主要限制了通過XMLHttpRequest實(shí)現(xiàn)的Ajax請(qǐng)求,如果請(qǐng)求的是一個(gè)“異源”地址,瀏覽器將不允許讀取返回的內(nèi)容
2.什么是跨域?跨域有幾種實(shí)現(xiàn)形式
①跨域:只要協(xié)議、域名、端口有任何一個(gè)不同,都被當(dāng)作是不同的域。為了突破同源策略的限制,跨域是指從一個(gè)網(wǎng)頁(yè)去請(qǐng)求另一個(gè)不同域的網(wǎng)頁(yè)的資源。
②跨域?qū)崿F(xiàn)形式:
1.降域:
對(duì)于主域相同而子域不同的例子,通過設(shè)置document.domain和iframe。
比如:可以在http://child1.a.com/a.html
和http://child2.a.com/b.html
兩個(gè)文件中分別加上document.domain = ‘a(chǎn).com’;然后通過a.html文件中創(chuàng)建一個(gè)iframe,去控制iframe的contentDocument,這樣兩個(gè)js文件之間就可以“交互”了.
2.jsonp(json with padding)
由于直接用 XMLHttpRequest 請(qǐng)求不同域上的數(shù)據(jù)是不可以的。這種方式主要是通過動(dòng)態(tài)插入一個(gè) script 標(biāo)簽。瀏覽器對(duì) script 的資源引用沒有同源限制,同時(shí)資源加載到頁(yè)面后會(huì)立即執(zhí)行(沒有阻塞的情況下) 。但只支持get請(qǐng)求,安全性不高
3.CORS(Cross-Origin Resource Sharing):
CORS 全稱是跨域資源共享(Cross-Origin Resource Sharing),是一種 ajax 跨域請(qǐng)求資源的方式,支持現(xiàn)代瀏覽器,IE支持10以上。
實(shí)現(xiàn)方式很簡(jiǎn)單,當(dāng)你使用 XMLHttpRequest 發(fā)送請(qǐng)求時(shí),瀏覽器發(fā)現(xiàn)該請(qǐng)求不符合同源策略,會(huì)給該請(qǐng)求加一個(gè)請(qǐng)求頭: Origin ,后臺(tái)進(jìn)行一系列處理,如果確定接受請(qǐng)求則在返回結(jié)果中加入一個(gè)響應(yīng)頭: Access-Control-Allow-Origin ; 瀏覽器判斷該相應(yīng)頭中是否包含 Origin 的值,如果有則瀏覽器會(huì)處理響應(yīng),我們就可以拿到響應(yīng)數(shù)據(jù),如果不包含瀏覽器直接駁回,這時(shí)我們無(wú)法拿到響應(yīng)數(shù)據(jù)。
4.HTML5 postMessage
即跨文檔消息傳輸,通過postMessage方法指明需要傳遞的數(shù)據(jù),以及目標(biāo)域名,接收端添加事件監(jiān)聽message,通過事件的origin屬性判斷發(fā)送請(qǐng)求的域名,符合要求就接收數(shù)據(jù),客戶端的方法和服務(wù)端的監(jiān)聽必須配套使用。
**5.其他Hack(利用hash、利用window.name) **
利用iframe和location.hash和window.name實(shí)現(xiàn)的跨域數(shù)據(jù)傳輸?shù)?br>
同源策略&跨域請(qǐng)求
JavaScript跨域總結(jié)與解決辦法
3.jsonp 的原理是什么
原理是利用script標(biāo)簽的可跨域性,在網(wǎng)頁(yè)中動(dòng)態(tài)的創(chuàng)建并添加script標(biāo)簽,然后在請(qǐng)求頁(yè)面的url上添加一個(gè)callback函數(shù)名作為參數(shù)。后臺(tái)服務(wù)器將數(shù)據(jù)放在一個(gè)指定名字的callback函數(shù)給傳回來,由于網(wǎng)頁(yè)已經(jīng)定義的callback函數(shù),參數(shù)被返回后,便會(huì)立即執(zhí)行。
4.CORS是什么
- CORS需要瀏覽器和服務(wù)器同時(shí)支持。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10;
- 瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息——origin字段,告訴跨域的后臺(tái)這次跨域請(qǐng)求是由哪個(gè)源發(fā)出的
- 實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器。只要服務(wù)器實(shí)現(xiàn)了CORS接口,就可以跨源通信。服務(wù)器根據(jù)前端發(fā)過來的跨域的ajax請(qǐng)求的origin字段,決定是否同意這次的跨域訪問;后臺(tái)可以通過設(shè)置一個(gè)標(biāo)頭決定是否通信
- 例如:假設(shè)我們現(xiàn)在需要從
http://www.test1.com
去http://www.test2.com
請(qǐng)求提取數(shù)據(jù),而JSONP只支持GET方法,這時(shí)候CORS就可以成為我們的選擇。
利用CORS,http://www.test2.com
只需要添加一個(gè)標(biāo)頭,就可以允許來自http://www.test1.com
的請(qǐng)求。在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ù),查看輸出報(bào)錯(cuò)
1.第一步,找到hosts文件
2.第二部,打開hosts。然后給本地默認(rèn)IP 127.0.0.1 綁定幾個(gè)域名,用于測(cè)試
4.第三步,用a.com/origin.html下的ajax給b.com/origin.php發(fā)請(qǐng)求,看跨域的時(shí)候數(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 頁(yè)面</div>
<script>
$.get('//b.com/origin.php',function(response){
console.log(response);
})
</script>
</body>
</html>
②origin.php代碼
<?php
echo 1234;
?>
③測(cè)試結(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 頁(yè)面</div>
<script>
function xxx(data){
alert(data);
};
var script=document.createElement('script');//添加動(dòng)態(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 頁(yè)面</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é)果: