javascript跨域解決方案(一)

來源:互聯網
上載者:User

 

1、神馬是跨域(Cross Domain)

說白點就是post、get的url不是你當前的網站,網域名稱不同。例如在aaa.com/a.html裡面,表單的提交action是bbb.com/b.html。

不僅如此,www.aaa.com和aaa.com之間也屬於跨域,因為www.aaa.com是次層網域,aaa.com是根網域名稱。

JavaScript出於安全方面的考慮,是不允許跨域調用其他頁面的對象的(同源策略 Same-Origin Policy)。

關於JavaScript能否跨域通訊的詳細說明,見下表:

http://www.a.com/a.js訪問以下URL的結果

URL 說明 是否允許通訊
http://www.a.com/b.js 同一網域名稱下 允許
http://www.a.com/script/b.js 同一網域名稱下不同檔案夾 允許
http://www.a.com:8000/b.js 同一網域名稱,不同連接埠 不允許
https://www.a.com/b.js 同一網域名稱,不同協議 不允許
http://70.32.92.74/b.js 網域名稱和網域名稱對應ip 不允許
http://script.a.com/b.js 主域相同,子域不同 不允許
http://a.com/b.js 同一網域名稱,不同次層網域(同上) 不允許
http://www.b.com/b.js 不同網域名稱 不允許

 

2、為嘛要跨域

跨域這東西其實很常見,例如我們可以把網站的一些指令碼、圖片或其他資源放到另外一個網站。例如我們可以使用Google提供的jQuery,載入時間少了,而且減少了伺服器的流量,如下

<script type="text/java script"src="https://aja x.googleapis.com/aj ax/libs/jquery/1.4.2/jquery.min.js"></script>

有時候不僅僅是一些指令碼、圖片這樣的資源,我們也會希望從另外的網站調用一些資料(有時候是不得不這樣),例如我希望擷取一些blog的RSS來產生一些內容,再或者說我在“人人開放平台”上開發一個應用,需要調用人人的資料。

然而,很不幸的是,直接用XMLHttpRequest來Get或者Post是不行的,例如我用jQuery的$.get去訪問本小博的主網域名稱 :

$.get("http://flycoder.org/",

{}, function(data){

alert('跨域不是越獄:'+data)

}, "html");

結果如下(總之就是不行啦~FF不報錯,但是木有返回資料):

 

那咋麼辦捏?(弱弱的說,測試的時候我發現IE訪問本地檔案時,是可以跨域的,不過這也沒啥用~囧~)

3、腫麼跨域

下面為了更好的講解和測試,我們可以通過修改hosts檔案來類比跨域的效果,hosts檔案在C:\Windows\System32\drivers\etc 檔案夾下。在下面加3行:

127.0.0.1 www.a.com

127.0.0.1 a.com

127.0.0.1 www.b.com

3.1、跨域代理

一種簡單的辦法,就是把跨域的工作交給伺服器,從後台擷取其他網站的資料再返回給前台,也就是跨域代理(Cross Domain Proxy)。

這種方法似乎蠻簡單的,改動也不太大。不過就是http請求多了些,響應慢了些,伺服器的負載重了些~

 

3.2、document.domain+iframe

 

 

對於主域相同而子域不同的例子,可以通過設定document.domain的辦法來解決。

舉www.a.com/a.html和a.com/b.html為例,只需在a.html中添加一個b.html的iframe,並且設定兩個頁面的document.domain都為'a.com'(只能為主網域名稱),兩個頁面之間即可互相訪問了,代碼如下:

www.a.com/a.html中的script

document.domain='a.com';

var ifr = document.createElement('iframe');

ifr.src = 'http://a.com/b.html';

ifr.style.display = 'none';

document.body.appendChild(ifr);

ifr.onload = function(){

  //擷取iframe的document對象

  //W3C的標準方法是iframe.contentDocument,

  //IE6、7可以使用document.frames[ID].document

  //為了更好相容,可先擷取iframe的window對象iframe.contentWindow

  var doc = ifr.contentDocument || ifr.contentWindow.document;

  // 在這裡操縱b.html

  alert(doc.getElementById("test").innerHTML);

};

 

a.com/b.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

<head>

<title></title>

<script type="text/javascript">

  document.domain='a.com';

</script>

</head>

<body>

<h1 id="test">Hello World</h1>

</body>

</html>

如果b.html要訪問a.html,可在子視窗(iframe)中通過window.parent來訪問父視窗的window對象,然後就可以為所欲為了(window對象都有了,還有啥不行的),同理子視窗也可以和子視窗之間通訊。

於是,我們可以通過b.html的XMLHttpRequest來擷取資料,再傳給a.html,從而解決跨子域擷取資料的問題。

但是這種方法只支援同一根網域名稱下的頁面,如果不同根網域名稱(例如baidu.com想訪問google.com)那就無能為力了。

 

3.3、動態script標籤(Dynamic Script Tag)

這種方法也叫“動態指令碼注入”。詳情

這種技術克服了XMLHttpRequest的最大限制,也就是跨域請求資料。直接用JavaScript建立一個新的指令碼標籤,然後設定它的src屬性為不同域的URL。

www.a.com/a.html中的script

var dynScript = document.createElement('script');

dynScript.src = 'http://www.b.com/b.js';

dynScript.setAttribute("type", "text/javascript");

document.getElementsByTagName('head')[0]

    .appendChild(dynScript);

通過動態標籤注入的必須是可執行檔JavaScript代碼,因此無論是你的資料格式是啥(xml、json等),都必須封裝在一個回呼函數中。一個回呼函數如下:

www.a.com/a.html中的script

function dynCallback(data){

  //處理資料, 此處簡單示意一下

  alert(data.content);

}

在這個例子中,www.b.com/b.js需要將資料封裝在上面這個dynCallback函數中,如下:

1

dynCallback({content:'Hello World'})

我們看到了讓人開心的結果,Hello World~

 

 

 

不過動態指令碼注入還是存在不少問題的,下面我們拿它和XMLHttpRequest來對比一下:

  XmlHttpRequest Dynamic Script Tag
跨瀏覽器安全色 No Yes
跨域限制 Yes No
接收HTTP狀態 Yes No (除了200)
支援Get、Post Yes No (GET only)
發送、接收HTTP頭 Yes No
接收XML Yes Yes
接收JSON Yes Yes
支援同步、非同步 Yes No (只能非同步)

 

可以看出,動態指令碼注入還是有不少限制,只能使用Get,不能像XHR一樣判斷Http狀態等。

而且使用動態指令碼注入的時候必須注意安全問題。因為JavaScript沒有任何許可權與存取控制的概念,通過動態指令碼注入的代碼可以完全控制整個頁面,所以引入外部來源的代碼必須多加小心

 

 

作者 jiangzhenghua

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.