Javascript跨域問題總結

    今天來總結下前端跨域問題的解決方案,網上有很多這個問題的總結和描述了;跨域問題也是前端的一個老問題了,現在就來簡單聊聊。

     同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響,它要求請求的協議,端口,域名一致。如果請求的協議,端口,域名任何一個不一樣,則出現跨域問題。同源策略的限制有2個:

 

  • 不能通過ajax的方法去請求不同源中的文檔
  • 不同域的iframe之間不能進行js交互操作

前端跨域問題時常出現,目前有以下7中常用的跨域解決方案:

1、JSONP

     大家耳熟能詳的一個解決跨域問題的方式是使用JSONP,實現的原理是:<script>標籤可以加載跨域的javascript腳本,並且被加載的腳本和當前文檔屬於同一個域。

     JSONP方式由2部分組成:回調函數數據callback回調函數是接受response響應在頁面中調用的函數,而數據就是傳入回調函數中的JSON數據。

    同時服務器端需要進行相應的處理,即請求的callback回調函數,並將運算產生的數據爲參數調用callback函數。

1. 前端向服務器發送請求,並帶上callback回調函數

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

   2.  後端接受請求獲取callback

<?php
$callback = $_GET['callback'];//得到回調函數名
$data = array('a','b','c');//要返回的數據
echo $callback.'('.json_encode($data).')';//輸出
?>

    如果項目中使用的jquery,jquery會自動生成一個全局函數來替換callback=?中的問號

<script type="text/javascript">
    $.getJSON('http://example.com/data.php?callback=?,function(jsondata)'){
        //處理獲得的json數據
    });
</script>

    $.getJSON方法會自動判斷是否跨域,不跨域就調用普通的ajax方法;跨域則會以異步加載js文件的形式來調用jsonp的回調函數。

 

2、iframe+domain

    通過設置document.domain共享cookie這種方式主要是用來跨子域。domain的設置有一定的限制,只能將domian設置成自身或更高一級的父域,且主域相同。

try {
  requestByFrame();
} catch (e) {
  document.domain = (location.host.match(/[^.]+\.[^.]+$/)[0]).replace(/:\d+/, "");
  //跨域
  var iframe = document.createElement("iframe");
  iframe.id = iframe.name = "proxyFrame";
  iframe.style.display = "none";

  var proxyUrl = location.protocol + "//" + main.domain + "/proxy.html?rnd=" + Math.random();
  iframe.src = proxyUrl;
  document.body.appendChild(iframe);
  iframe.onload = function() {
    requestByFrame();
  }
}

function requestByFrame() {
  var win = frames["proxyFrame"];
  if (win.location.host === top.location.host) {
    throw "error";
  } else {
    conf.xhr = new win.XMLHttpRequest;
    ajax(conf);
    //...
  }
}

 

3、postMessage

    html5中新增了window.postMessage(message,targetOrigin) 方法,可以使用它來向其它的window對象發送消息。無論這個window對象是屬於同源或不同源,目前IE8+、FireFox、Chrome、Opera等瀏覽器都已經支持。

    postMessage(message,targetOrigin)接受2個參數,第一個參數message是是消息體,支持字符串和對象;第二個參數目標域名,可設置成*,表示所有的域都可以接受消息;

window.parent.postMessage({
    act:'response',
    msg:{
       answer:url
    }
},'a.cn');

在目標域a.cn中接收postMessage發送過來的消息體

//a.cn中監聽第三方postMessage發送過來的消息
window.addEventListener('message', function(e){
  if (e.data.act == 'response' && e.origin.indexOf("a.cn") > -1) {
      var answer = e.data.msg.answer;
      if(answer.indexOf("http://") > -1 || answer.indexOf("https://") > -1){
         alert(e.data.msg.answer);
      }
      
  } else {
      console.log('未定義的消息: '+ e.data.act);
  }
}, false);

 

4、CORS

 

    CORS(Cross-origin resource sharing)跨域資源共享適用於通過XMLHttpRequest / XDomainRequest請求接口的情形,其思想是使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功,還是應該失敗。

    實現CORS跨域,需要服務器進行配置,主要是三點:允許跨域的域名(Access-Control-Allow-Origin),允許請求的方法(Access-Control-Allow-Methods),允許請求的方式(Access-Control-Allow-Headers)。

CORS 和 JSONP的區別:
    1.JSONP只支持GET方式,CORS支持所有的HTTP請求;
    2.CORS可以像普通的XMLHttpRequest發起請求和獲得數據;
    3.JSONP主要被老的瀏覽器支持,它們往往不支持CORS,而絕大多數現代瀏覽器都已經支持了CORS);

詳細介紹可參看CORS詳解

 

5、nginx反向代理

    利用nginx反向代理來實現跨域請求是目前大部分公司採用的方式。

    

在nginx中增加location反向代理到服務器端設置:

server {
    listen       80;
    server_name  serverName; 
    location /m/ {
        proxy_pass http://example/xxx/api; //將/m/的請求轉發example上
    }
}

6、WebSocket

    利用WebSocket可以進行跨域訪問的原因是因爲WebSocket使用ws://(非加密)和wss://(加密)作爲協議,該協議不實行同源政策,所以可以進行跨域請求。

 

7、window.name

 

     window對象有個name屬性,在一個窗口(window)的生命週期內,窗口載入的所有的頁面都是共享一個window.name的,每個頁面對window.name都有讀寫的權限,window.name是持久存在一個窗口載入過的所有頁面中的,window.name大小2M左右。

    實現:a.html跨域請求不同域中的data.html內的window.name數據,在a.html 新建一個隱藏的proxy的iframe  ,iframe.src ='xxx/b.html',設置iframe的的onload方法,在onload function中獲取b.html中的window.name值,再設置iframe的src爲與a.html同源的b.html或者爲about:blank。

    例如:在index中,創建一個index2.設置對應的window.name.然後修改href到對應的iframe頁面.處理完成後由iframe修改href返回到index域下的某個頁面,讀取window.name。

 

跨域總結完成,如有紕漏歡迎指正~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章