2025-03-25

 

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不報錯,但是木有返回數據):

 

vc3MtZG9tYWlu” width=”364″ />

那咋麼辦捏?(弱弱的說,測試的時候我發現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

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *