AJAX跨域的解決辦法? 同步非同步

來源:互聯網
上載者:User

標籤:des   style   blog   http   os   io   使用   java   strong   

1. HTTP協議的狀態訊息都有哪些?

1**:請求收到,繼續處理
2**:操作成功收到,分析、接受
3**:完成此請求必須進一步處理
4**:請求包含一個錯誤文法或不能完成
5**:伺服器執行一個完全有效請求失敗

 

 

 

2. AJAX跨域的解決辦法?

 

1、document.domain+iframe的設定

 

  對於主域相同而子域不同的例子,可以通過設定document.domain的辦法來解決。 具體的做法是可以在http://www.a.com/a.html和http://script.a.com/b.html兩個檔案中分別加上 document.domain = a.com;然後通過a.html檔案中建立一個iframe,去控制iframe的contentDocument,這樣兩個js檔案之間就可以互動 了。當然這種辦法只能解決主域相同而次層網域不同的情況,如果你異想天開的把script.a.com的domian設為alibaba.com那顯然是 會報錯地!代碼如下:

 

  www.a.com上的a.html

 

document.domain =‘a.com‘;
var ifr = document.createElement(‘iframe‘);
ifr.src =‘http://script.a.com/b.html‘;
ifr.style.display =‘none‘;
document.body.appendChild(ifr);
ifr.onload =function(){
var doc = ifr.contentDocument || ifr.contentWindow.document;
// 在這裡操縱b.html
alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);
};

script.a.com上的b.html

document.domain =‘a.com‘;

 

  這種方式適用於{www.kuqin.com, kuqin.com, script.kuqin.com, css.kuqin.com}中的任何頁面相互連信。

 

  備忘:某一頁面的domain預設等於window.location.hostname。主網域名稱是不帶www的網域名稱,例如a.com,主網域名稱前面帶首碼的通常都為次層網域或多級網域名稱,例如www.a.com其實是次層網域。 domain只能設定為主網域名稱,不可以在b.a.com中將domain設定為c.a.com。

 

  問題:
1、安全性,當一個網站(b.a.com)被攻擊後,另一個網站(c.a.com)會引起安全性漏洞。
2、如果一個頁面中引入多個iframe,要想能夠操作所有iframe,必須都得設定相同domain。

 

  2、動態建立script

 

  雖然瀏覽器預設禁止了跨域訪問,但並不禁止在頁面中引用其他域的JS檔案,並可以自由執行引入的JS檔案中的function(包括操作cookie、Dom等等)。根據這一點,可以方便地通過建立script節點的方法來實現完全跨域的通訊。具體的做法可以參考YUI的Get Utility

 

  這裡判斷script節點載入完畢還是蠻有意思的:ie只能通過script的readystatechange屬性,其它瀏覽器是script的load事件。以下是部分判斷script載入完畢的方法。

 

js.onload = js.onreadystatechange =function() {
if (!this.readyState ||this.readyState ===‘loaded‘||this.readyState ===‘complete‘) {
// callback在此處執行
js.onload = js.onreadystatechange =null;
}
};

 

  3、利用iframe和location.hash

 

  這個辦法比較繞,但是可以解決完全跨域情 況下的腳步置換問題。原理是利用location.hash來進行傳值。在url: http://a.com#helloword中的#helloworld就是location.hash,改變hash並不會導致頁面重新整理,所以可以利 用hash值來進行資料傳遞,當然資料容量是有限的。假設網域名稱a.com下的檔案cs1.html要和cnblogs.com網域名稱下的cs2.html傳 遞資訊,cs1.html首先建立自動建立一個隱藏的iframe,iframe的src指向cnblogs.com網域名稱下的cs2.html頁面,這時 的hash值可以做參數傳遞用。

 

  cs2.html響應請求後再將通過修改cs1.html的hash值來傳遞資料(由於兩個頁面不在同一個域下IE、Chrome不允許修改parent.location.hash的值,所以要藉助於a.com網域名稱下的一個代理iframe;Firefox可以修改)。同時在cs1.html上加一個定時器,隔一段時間來判斷location.hash的值有沒有變化,一點有變化則擷取擷取hash值。代碼如下:

 

  先是a.com下的檔案cs1.html檔案:

 

function startRequest(){
var ifr = document.createElement(‘iframe‘);
ifr.style.display =‘none‘;
ifr.src =‘http://www.cnblogs.com/lab/cscript/cs2.html#paramdo‘;
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);

cnblogs.com網域名稱下的cs2.html:

//類比一個簡單的參數處理操作
switch(location.hash){
case‘#paramdo‘:
callBack();
break;
case‘#paramset‘:
//do something……
break;
}

function callBack(){
try {
parent.location.hash =‘somedata‘;
} catch (e) {
// ie、chrome的安全機制無法修改parent.location.hash,
// 所以要利用一個中間的cnblogs域下的代理iframe
var ifrproxy = document.createElement(‘iframe‘);
ifrproxy.style.display =‘none‘;
ifrproxy.src =‘http://a.com/test/cscript/cs3.html#somedata‘; // 注意該檔案在"a.com"域下
document.body.appendChild(ifrproxy);
}
}

 

  a.com下的網域名稱cs3.html

 

//因為parent.parent和自身屬於同一個域,所以可以改變其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);

 

  當然這樣做也存在很多缺點,諸如資料直接暴露在了url中,資料容量和類型都有限等……

 

  4、window.name實現的 跨域資料轉送

 

  文章較長列在此處不便於閱讀,詳細請看 window.name實現的跨域資料轉送。

 

  5、使用HTML5 postMessage

 

  HTML5中最酷的新功能之一就是 跨文檔訊息傳輸Cross Document Messaging。下一代瀏覽器都將支援這個功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已經使用了這個功能,用postMessage支援基於web的即時訊息傳遞。

 

otherWindow.postMessage(message, targetOrigin);

 

otherWindow: 對接收資訊頁面的window的引用。可以是頁面中iframe的contentWindow屬性;window.open的傳回值;通過name或下標從window.frames取到的值。
message: 所要發送的資料,string類型。
targetOrigin: 用於限制otherWindow,*表示不作限制

 

  a.com/index.html中的代碼:

 

 iframe id="ifr" src="b.com/index.html" /iframe
 script type="text/javascript"
window.onload =function() {
var ifr = document.getElementById(‘ifr‘);
var targetOrigin =‘http://b.com‘; // 若寫成‘http://b.com/c/proxy.html‘效果一樣
// 若寫成‘http://c.com‘就不會執行postMessage了
ifr.contentWindow.postMessage(‘I was there!‘, targetOrigin);
};
/script

 

  b.com/index.html中的代碼:

 

script type="text/javascript"
window.addEventListener(‘message‘, function(event){
// 通過origin屬性判斷訊息來源地址
if (event.origin ==‘http://a.com‘) {
alert(event.data); // 彈出"I was there!"
alert(event.source); // 對a.com、index.html中window對象的引用
// 但由於同源策略,這裡event.source不可以訪問window對象
}
}, false);
/script

 

  6、利用flash

 

  這是從YUI3的IO組件中看到的辦法,具體可見http://developer.yahoo.com/yui/3/io/。
  可以看在Adobe Developer Connection看到更多的跨域代理檔案規格:ross-Domain Policy File Specifications、HTTP Headers Blacklist。

 

 

 

 

 

3. 同步和非同步區別?

 

一、同步載入與非同步載入的形式

 

1. 同步載入

 

我們平時最常使用的就是這種同步載入形式:

 

<script src="http://yourdomain.com/script.js"></script> 

 

同步模式,又稱阻塞模式,會阻止瀏覽器的後續處理,停止了後續的解析,因此停止了後續的檔案載入(像)、渲染、代碼執行。 js 之所以要同步執行,是因為 js 中可能有輸出 document 內容、修改dom、重新導向等行為,所以預設同步執行才是安全的。以前的一般建議是把<script>放在頁面末尾</body>之前,這樣儘可能減少這種阻塞行為,而先讓頁面展示出來。

 

簡單說:載入的網路 timeline 是瀑布模型,而非同步載入的 timeline 是並行存取模型。

2. 常見非同步載入(Script DOM Element)

(function() {
var s = document.createElement(‘script‘);
s.type = ‘text/javascript‘;
s.async = true;
s.src = ‘http://yourdomain.com/script.js‘;
var x = document.getElementsByTagName(‘script‘)[0];
x.parentNode.insertBefore(s, x);
})();

非同步載入又叫非阻塞,瀏覽器在下載執行 js 同時,還會繼續進行後續頁面的處理。

 

這種方法是在頁面中<script>標籤內,用 js 建立一個 script 元素並插入到 document 中。這樣就做到了非阻塞的下載 js 代碼。

 

async屬性是HTML5中新增的非同步支援,見後文解釋,加上好(不加也不影響)。

 

此方法被稱為 Script DOM Element 法,不要求 js 同源。

 

將js程式碼封裝裹在匿名函數中並立即執行的方式是為了保護變數名泄露到外部可見,這是很常見的方式,尤其是在 js 庫中被普遍使用。

 

例如 Google Analytics 和 Google+ Badge 都使用了這種非同步載入代碼:
(function() {
var ga = document.createElement(‘script‘); ga.type = ‘text/javascript‘; ga.async = true;
ga.src = (‘https:‘ == document.location.protocol ? ‘https://ssl‘ : ‘http://www‘) + ‘.google-analytics.com/ga.js‘;
var s = document.getElementsByTagName(‘script‘)[0]; s.parentNode.insertBefore(ga, s);
})();
(function()
    {var po = document.createElement("script");
po.type = "text/javascript"; po.async = true;po.src = "https://apis.google.com/js/plusone.js";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(po, s);
})();
但是, 這種載入方式在載入執行完之前會阻止 onload 事件的觸發,而現在很多頁面的代碼都在 onload 時還要執行額外的渲染工作等,所以還是會阻塞部分頁面的初始化處理。  3. onload 時的非同步載入

 

(function() {
function async_load(){
var s = document.createElement(‘script‘);
s.type = ‘text/javascript‘;
s.async = true;
s.src = ‘http://yourdomain.com/script.js‘;
var x = document.getElementsByTagName(‘script‘)[0];
x.parentNode.insertBefore(s, x);
}
if (window.attachEvent)
window.attachEvent(‘onload‘, async_load);
else
window.addEventListener(‘load‘, async_load, false);
})();

 

這和前面的方式差不多,但關鍵是它不是立即開始非同步載入 js ,而是在 onload 時才開始非同步載入。這樣就解決了阻塞 onload 事件觸發的問題。

 

補充: DOMContentLoaded 與 OnLoad 事件

 

DOMContentLoaded : 頁面(document)已經解析完成,頁面中的dom元素已經可用。但是頁面中引用的圖片、subframe可能還沒有載入完。

 

OnLoad:頁面的所有資源都載入完畢(包括圖片)。瀏覽器的載入進度在這時才停止。

 

這兩個時間點將頁面載入的timeline分成了三個階段。

4.非同步載入的其它方法

由於Javascript的 動態特性,還有很多非同步載入方法:

 

  • XHR Eval 
  • XHR Injection
  • Script in Iframe
  • Script Defer
  • document.write Script Tag
  • 還有一種方法是用 setTimeout 延遲0秒 與 其它方法組合。

 

XHR Eval :通過 ajax 擷取js的內容,然後 eval 執行。

 

var xhrObj = getXHRObject(); 
xhrObj.onreadystatechange =
function() {
if ( xhrObj.readyState != 4 ) return;
eval(xhrObj.responseText);
};
xhrObj.open(‘GET‘, ‘A.js‘, true);
xhrObj.send(‘‘);

 

Script in Iframe:建立並插入一個iframe元素,讓其非同步執行 js 。

 

var iframe = document.createElement(‘iframe‘); 
document.body.appendChild(iframe);
var doc = iframe.contentWindow.document;
doc.open().write(‘<body onload="insertJS()">‘);
doc.close();

 

GMail Mobile:頁內 js 的內容被注釋,所以不會執行,然後在需要的時候,擷取script元素中 text 內容,去掉注釋後 eval 執行。

 

<script type="text/javascript"> 
/*
var ...
*/
</script>

  

AJAX跨域的解決辦法? 同步非同步

相關文章

聯繫我們

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