首頁  >  文章  >  web前端  >  JS跨域問題詳解_基礎知識

JS跨域問題詳解_基礎知識

WBOY
WBOY原創
2016-05-16 16:30:281305瀏覽

JavaScript是一種在Web開發中經常使用的前端動態腳本技術。在JavaScript中,有一個很重要的安全性限制,被稱為「Same-Origin Policy」(同源策略)。這個策略對於JavaScript程式碼能夠存取的頁面內容做了很重要的限制,即JavaScript只能存取與包含它的文件在同一域下的內容。

  JavaScript這個安全策略在進行多iframe或多視窗程式設計、以及Ajax程式設計時顯得格外重要。根據這個策略,在baidu.com下的頁面中包含的JavaScript程式碼,不能存取在google.com網域下的頁面內容;甚至不同的子網域之間的頁面也不能透過JavaScript程式碼互相存取。對於Ajax的影響在於,透過XMLHttpRequest實現的Ajax請求,不能向不同的網域提交請求,例如,在abc.example.com下的頁面,不能向def.example.com提交Ajax請求,等等。

  然而,當進行一些比較深入的前端編程的時候,不可避免地需要進行跨域操作,這時候「同源策略」就顯得過於苛刻。本文就這個問題,概括了跨域所需的一些技術。

  下面我們分兩種情況討論跨域技術:首先討論不同子域的跨域技術,然後討論完全不同域的跨域技術。

(一)不同子域的跨域技術。
  我們分成兩個問題來分別討論:第一個問題是如何跨不同子域進行JavaScript呼叫;第二個問題是如何向不同子域提交Ajax請求。

先來解決第一個問題,假設example.com網域下有兩個不同子網域:abc.example.com和def.example.com。現在假設在def.example.com下面有一個頁面,裡面定義了一個JavaScript函數:

複製程式碼 程式碼如下:

function funcInDef() {
   .....
}

  我們想要在abc.example.com下的某個頁面中呼叫上面的函數。再假設我們要討論的abc.example.com下面的這個頁面是以iframe形式嵌入在def.example.com下面那個頁面裡的,這樣我們可能試圖在iframe裡做如下調用:

複製程式碼 程式碼如下:

window.top.funcInDef();

   好,我們注意到,這個呼叫是被前面講到的「同源策略」所禁止的,JavaScript引擎會直接拋出一個例外。

  為了實現上述調用,我們可以透過修改兩個頁面的domain屬性的方法來做到。例如,我們可以將上面在abc.example.com和def.example.com下的兩個頁面的頂端都加上如下的JavaScript程式碼片段:

複製程式碼 程式碼如下:



  這樣,兩個頁面就變成同域了,前面的呼叫也可以正常執行了。

  這裡要注意的一點是,一個頁面的document.domain屬性只能設定成一個更頂級的網域(除了一級網域),但不能設定成比目前網域更深層的子網域。例如,abc.example.com的頁面只能將它的domain設定成example.com,不能設定成sub.abc.example.com,當然也不能設定成一級網域com。

  上面的例子討論的是兩個頁面屬於iframe嵌套關係的情況,當兩個頁面是打開與被打開的關係時,原理也完全一樣。

  下面我們來解決第二個問題:如何向不同子網域提交Ajax請求。

  通常情況下,我們會使用與下面類似的程式碼來建立一個XMLHttpRequest物件:

複製程式碼 程式碼如下:

factories = [
    function() { return new XMLHttpRequest(); },
    function() { return new ActiveXObject("Msxml2.XMLHTTP"); },
    function() { return new ActiveXObject("Microsoft.XMLHTTP"); }
];
function newRequest() {
    for(var i = 0; i factories.length; i ) {
        try{
            var factory = factories[i];
            return factory();
        } catch(e) {}
    }
    return null;
}

 

  上面的程式碼中引用ActiveXObject,是為了相容於IE6系列瀏覽器。每次我們呼叫newRequest函數,就獲得了一個剛剛建立的Ajax對象,然後用這個Ajax物件來發送HTTP請求。例如,下面的程式碼向abc.example.com發送了一個GET請求:

複製程式碼 程式碼如下:

var request = newRequest();
request.open("GET", "http://abc.example.com" );
request.send(null);

  假設上面的程式碼包含在一個abc.example.com網域下的頁面裡,則這個GET請求可以正常發送成功,沒有任何問題。然而,如果現在要向def.example.com發送請求,則出現跨域問題,JavaScript引擎拋出例外。

  解決的方法是,在def.example.com域下放置一個跨域文件,假設叫crossdomain.html;然後將前面的newRequest函數的定義移到這個跨域文件中;最後像之前修改document. domain值的做法一樣,在crossdomain.html檔案和abc.example.com域下呼叫Ajax的頁面頂端,都加上:

複製程式碼 程式碼如下:


  為了使用跨域文件,我們在abc.example.com域下調用Ajax的頁面中嵌入一個隱藏的指向跨域文件的iframe,例如:

[code]
>

  這時abc.example.com域下的頁面和跨域文件crossdomain.html都在同一個域(example.com)下,我們可以在abc.example.com域下的頁面中去調用crossdomain. html中的newRequest函數:

複製程式碼 程式碼如下:

var request = window.frames["xd_iframe"].newRequest();

  這樣取得的request對象,就可以向http://def.example.com發送HTTP請求了。

(二)完全不同域的跨域技術。
  如果頂級域名都不相同,例如example1.com和example2.com之間想透過JavaScript在前端通信,則所需的技術更複雜些。

  在講解不同域的跨域技術之前,我們首先明確一點,下面要講的技術也同樣適用於前面跨不同子域的情況,因為跨不同子域只是跨域問題的一個特例。當然,在適當的情況下使用適當的技術,能夠確保更優的效率和更高的穩定性。

  簡言之,根據不同的跨域需求,跨域技術可以歸為下面幾類:

1、JSONP跨域GET請求
2、透過iframe實現跨域
3、flash跨域HTTP請求
4、window.postMessage

本文先到這裡,後續我們再詳細介紹上面提到的4種跨域技術,稍後就奉上!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn