31.同源策略、跨域、jsonp

問答

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.jshttp://jirengu.com/index.php (同源)
  • 同源策略的意思是只有同源的客戶端腳本比如js,才可以讀寫對(duì)方的資源;
    不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對(duì)方的資源。比如a.com下的js不能讀取b.com下的資源
  • 不同源的例子:
    http://jirengu.com/main.jshttps://jirengu.com/a.php(協(xié)議不同)
    http://jirengu.com/main.jshttp://bbs.jirengu.com/a.php(域名不同,域名必須完全相同才可以)
    http://jiengu.com/main.jshttp://jirengu.com:8080/a.php (端口不同,第一個(gè)是80)

注意

  • 對(duì)于當(dāng)前頁(yè)面來說頁(yè)面存放的JS 文件的域不重要,重要的是加載該 JS 頁(yè)面所在什么域。比如<script>標(biāo)簽引用了來源于不同地方http://www.artech.comhttp://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.htmlhttp://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.comhttp://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的需求了

跨資源共享 CORS 詳解

代碼

1.本地搭建服務(wù)器,演示同源策略

本地搭建服務(wù)器(如果使用 SAE 可創(chuàng)建不同的代碼版本,這樣可通過1.xxx.sinapp.com2.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文件


Paste_Image.png

2.第二部,打開hosts。然后給本地默認(rèn)IP 127.0.0.1 綁定幾個(gè)域名,用于測(cè)試


Paste_Image.png

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é)果


Paste_Image.png

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é)果:

Paste_Image.png

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é)果:

Paste_Image.png


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容