JSON跨域解決方案收集

來源:互聯網
上載者:User

標籤:.com   等等   伺服器   能力   localhost   elf   難題   不同   res   

 

最近面試問的挺多的一個問題,就是JavaScript的跨域問題。在這裡,對跨域的一些方法做個總結。由於瀏覽器的同源策略,不同網域名稱、不同連接埠、不同協議都會構成跨域;但在實際的業務中,很多情境需要進行跨域傳遞資訊,這樣就催生出多種跨域方法。

1. 具備src的標籤
  • 原理:所有具有 src 屬性的HTML標籤都是可以跨域的

在瀏覽器中, <script> 、 <img> 、 <iframe> 和 <link> 這幾個標籤是可以載入跨域(非同源)的資源的,並且載入的方式其實相當於一次普通的GET請求,唯一不同的是,為了安全起見,瀏覽器不允許這種方式下對載入到的資源的讀寫操作,而只能使用標籤本身應當具備的能力(比如指令碼執行、樣式應用等等)。

2. JSONP跨域
  • 原理: <script> 是可以跨域的,而且在跨域指令碼中可以直接回調當前指令碼的函數

script標籤是可以載入異域的JavaScript並執行的,通過預先設定好的callback函數來實現和母頁面的互動。它有一個大名,叫做JSONP跨域,JSONP是JSON with Padding的略稱。它是一個非官方的協議,明明是載入script,為啥和JSON扯上關係呢?原來就是這個callback函數,對它的使用有一個典型的方式,就是通過JSON來傳參,即將JSON資料填充進回呼函數,這就是JSONP的JSON+Padding的含義。JSONP只支援GET請求。

前端代碼:

<script type="text/javascript"> function dosomething(jsondata){ //處理獲得的json資料 }</script><script src="http://haorooms.com/data.php?callback=dosomething"></script>

後台代碼:

<?php$callback = $_GET[‘callback‘];//得到回呼函數名$data = array(‘a‘,‘b‘,‘c‘);//要返回的資料echo $callback.‘(‘.json_encode($data).‘)‘;//輸出?>
3. 跨域資源共用(CORS)
  • 原理:伺服器設定Access-Control-Allow-Origin HTTP回應標頭之後,瀏覽器將會允許跨域請求

CORS是HTML5標準提出的跨域資源共用(Cross Origin Resource Share),支援GET、POST等所有HTTP請求。CORS需要伺服器端設定 Access-Control-Allow-Origin 頭,否則瀏覽器會因為安全性原則攔截返回的資訊。

Access-Control-Allow-Origin: *              # 允許所有網域名稱訪問,或者Access-Control-Allow-Origin: http://a.com   # 只允許所有網域名稱訪問

CORS又分為簡單跨域和非簡單跨域請求,有關CORS的詳細介紹請看 阮一峰 的 跨域資源共用 CORS 詳解 ,裡面講解的非常詳細。

4. document.domain
  • 原理:相同主網域名稱不同子網域名稱下的頁面,可以設定document.domain讓它們同域

我們只需要在跨域的兩個頁面中設定document.domain就可以了。修改document.domain的方法只適用於不同子域的架構間的互動,要載入iframe頁面。

例如:1. 在頁面 http://a.example.com/a.html 設定document.domain

<iframe id = "iframe" src="http://b.example.com/b.html" onload = "test()"></iframe><script type="text/javascript"> document.domain = ‘example.com‘;//設定成主域 function test(){ alert(document.getElementById(‘?iframe‘).contentWindow);//contentWindow 可取得子視窗的 window 對象 }</script>

2、在頁面http:// b.example.com/b.html 中設定document.domain

<script type="text/javascript"> document.domain = ‘example.com‘;//在iframe載入這個頁面也設定document.domain,使之與首頁面的document.domain相同</script>
5. window.name
  • 原理:window對象有個name屬性,該屬性有個特徵:即在一個視窗(window)的生命週期內,視窗載入的所有的頁面都是共用一個window.name的,每個頁面對window.name都有讀寫的許可權,window.name是持久存在一個視窗載入過的所有頁面中的。

這裡有三個頁面:

  • sever.com/a.html 資料存放頁面

  • agent.com/b.html 資料擷取頁面

  • agent.com/c.html 空頁面,做代理使用

a.html中,設定 window.name 作為需要傳遞的值

<script> window.name = ‘I was there!‘; alert(window.name);</script>

b.html中,當iframe載入後將iframe的 src 指向同域的 c.html ,這樣就可以利用 iframe.contentWindow.name 擷取要傳遞的值了

<body>  <script type="text/javascript"> iframe = document.createElement(‘iframe‘); iframe.style.display = ‘none‘; var state = 0; iframe.onload = function() { if(state === 1) { var data = JSON.parse(iframe.contentWindow.name); alert(data); iframe.contentWindow.document.write(‘‘); iframe.contentWindow.close(); document.body.removeChild(iframe); } else if(state === 0) { state = 1; iframe.contentWindow.location = ‘http://agent.com/c.html‘; } }; iframe.src = ‘http://sever.com/a.html‘; document.body.appendChild(iframe); </script></body>

成功擷取跨域資料,效果如下:

6. window.postMesage
  • 原理: HTML5新增的postMessage方法,通過postMessage來傳遞資訊,對方可以通過監聽message事件來監聽資訊。可跨主網域名稱及雙向跨域。

這裡有兩個頁面:

  1. agent.com/index.html

  2. server.com/remote.html

本地代碼index.html

<body>      <iframe id="proxy" src="http://server.com/remote.html" onload = "postMsg()" style="display: none" ></iframe>      <script type="text/javascript">  var obj = {  msg: ‘hello world‘  }  function postMsg (){  var iframe = document.getElementById(‘proxy‘);  var win = iframe.contentWindow;  win.postMessage(obj,‘http://server.com‘);  }  </script>  </body>

postMessage 的使用方法: otherWindow.postMessage(message, targetOrigin);

  • otherWindow: 指目標視窗,也就是給哪個window發訊息,是 window.frames 屬性的成員或者由 window.open 方法建立的視窗

  • message: 是要發送的訊息,類型為 String、Object (IE8、9 不支援)

  • targetOrigin: 是限定訊息接收範圍,不限制請使用 ‘*’

server.com上remote.html,監聽 message 事件,並檢查來源是否是要通訊的域。

<head>    <title></title>    <script type="text/javascript">        window.onmessage = function(e){            if(e.origin !== ‘http://localhost:8088‘) return;            alert(e.data.msg+" from "+e.origin);        }    </script></head>

7. location.hash

原理:

  • 這個辦法比較繞,但是可以解決完全跨域情況下的腳步置換問題。原理是利用location.hash來進行傳值。www.a.com下的a.html想和www.b.com下的b.html通訊(在a.html中動態建立一個b.html的iframe來發送請求)

  • 但是由於“同源策略”的限制他們無法進行交流(b.html無法返回資料),於是就找個中間人:www.a.com下的c.html(注意是www.a.com下的)。

  • b.html將資料傳給c.html(b.html中建立c.html的iframe),由於c.html和a.html同源,於是可通過c.html將返回的資料傳回給a.html,從而達到跨域的效果。

a.html代碼如下:

<script>function startRequest(){  var ifr = document.createElement(‘iframe‘);  ifr.style.display = ‘none‘;  ifr.src = ‘http://www.b.com/b.html#sayHi‘; //傳遞的location.hash  document.body.appendChild(ifr); } function checkHash() {  try {  var data = location.hash ? location.hash.substring(1) : ‘‘;  if (console.log) {  console.log(‘Now the data is ‘+data);  }  } catch(e) {}; } setInterval(checkHash, 2000); window.onload = startRequest;</script>

b.html代碼如下:

<script>function checkHash(){ var data = ‘‘; //類比一個簡單的參數處理操作 switch(location.hash){ case ‘#sayHello‘: data = ‘HelloWorld‘;break; case ‘#sayHi‘: data = ‘HiWorld‘;break; default: break; } data && callBack(‘#‘+data);}function callBack(hash){ // ie、chrome的安全機制無法修改parent.location.hash,所以要利用一個中間的www.a.com域下的代理iframe var proxy = document.createElement(‘iframe‘); proxy.style.display = ‘none‘; proxy.src = ‘http://localhost:8088/proxy.html‘+hash; // 注意該檔案在"www.a.com"域下 document.body.appendChild(proxy);}window.onload = checkHash;</script>

由於兩個頁面不在同一個域下,IE、Chrome不允許修改parent.location.hash的值,所以要藉助於a.com網域名稱下的一個代理iframe,這裡有一個a.com下的代理檔案c.html。Firefox可以修改。

c.html代碼如下:

<script>parent.parent.location.hash = self.location.hash.substring(1); </script>

直接存取a.html,a.html向b.html發送的訊息為”sayHi”;b.html通過訊息判斷返回了”HiWorld”,並通過c.html改變了location.hash的值

8. flash URLLoader

flash有自己的一套安全性原則,伺服器可以通過crossdomain.xml檔案來聲明能被哪些域的SWF檔案訪問,SWF也可以通過API來確定自身能被哪些域的SWF載入。當跨域訪問資源時,例如從域baidu.com請求域google.com上的資料,我們可以藉助flash來發送HTTP請求。首先,修改域google.com上的crossdomain.xml(一般存放在根目錄,如果沒有需要手動建立) ,把baidu.com加入到白名單。其次,通過Flash URLLoader發送HTTP請求,最後,通過Flash API把響應結果傳遞給JavaScript。Flash URLLoader是一種很普遍的跨域解決方案,不過需要支援iOS的話,這個方案就不可行了。

小結

總的來說,常見的跨域方法如上述。在不同的業務情境下,各有適合的跨域方式。跨域解決了一些資源共用、資訊互動的難題,但是有的跨域方式可能會帶來安全問題,如jsonp可導致水坑攻擊,等標籤會被用來進行xss或csrf攻擊。所以,在應用跨域的情境,需要格外注意安全問題。

 公眾號原文

JSON跨域解決方案收集

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.