HTML5:使用postMessage實現Ajax跨域請求

來源:互聯網
上載者:User

由於同源策略的限制,Javascript存在跨域通訊的問題,典型的跨域問題有iframe與父級的通訊等。

常規的幾種解決方案:
(1) document.domain+iframe; (2) 動態建立script; (3) iframe+location.hash; (4) flash。

這裡不細說這幾種方法,記錄的是HTML5的window.postMessage。postMessage相容IE8+、Firefox、Opera、Safari、Chrome

需要兩個異域的伺服器來做測試,當然也可以用本地和線上伺服器作為兩個異域的伺服器。假如使用phonegap開發,就可以將請求檔案安裝在用戶端,然後動態請求伺服器的資料處理,獲得並顯示資料。這樣就可以用任意Web開發語言及方法來開發phonegap App所需的後台。

1.  postMessage的用法

postMessage是HTML5為解決js跨域問題而引入的新的API,允許多個iframe/window跨域通訊。

假設有結構如下:

test.html
<section id="wrapper">
<header>
<h1>postMessage (跨域)</h1>
</header>
<article>
<form>
<p>
<label for="message">給iframe發一個資訊:</label>
<input type="text" name="message" value="son" id="message" />
<input type="submit" />
</p>
</form>
<h4>目標iframe傳來的資訊:</h4>
<p id="test">暫無資訊</p>
<iframe id="iframe"
src="http://xiebiji.com/works/postmessage/iframe.html"></iframe>
</article>
</section>

  

iframe.html
<strong>iframe指向xiebiji.com</strong>
<form>
<p>
<label for="message">給父視窗發個資訊:</label>
<input type="text" name="message" value="dad" id="message" />
<input type="submit" />
</p>
</form>
<p id="test">暫無資訊。</p>
下面是test.html裡的Javascript代碼(發送資料):

var win = document.getElementById("iframe").contentWindow;
document.querySelector('form').onsubmit=function(e){
win.postMessage(document.getElementById("message").value,"*");
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}

  關鍵代碼就一句:

win.postMessage(document.getElementById("message").value,"*");

  postMessage是通訊對象的一個方法,所以向iframe通訊,就是iframe對象調用postMessage方法。postMessage有兩個參數,缺一不可。第一個參數是要傳遞的資料,第二個參數是允許通訊的域,“*”代表不對訪問的域進行判斷,可理解為允許所有域的通訊。

  然後是iframe.html裡偵聽接收資料的代碼:

var parentwin = window.parent;
window.onmessage=function(e){
document.getElementById("test").innerHTML = e.origin + "say:" + e.data;
parentwin.postMessage('HI!你給我發了"<span>'+e.data+'"</span>。',"*");
};

  很簡單,相信一看就懂了。e.data包含傳送過來的資料,e.origin指代源域。

然後iframe.html也給test.html發送回應的資料,test.html接收資料。代碼雷同,就不貼代碼了。

點此查看Demo(代碼素Joe哥給的)

2. Ajax跨域請求

基於以上的跨域通訊,只要將Ajax代碼放在iframe.html裡的onmessage處理函數裡頭,將test.html用postMessage傳過來的資料作為參數發送請求,再將返回的資料用postMessage傳給test.html。這樣就實現了跨域的Ajax請求。其實是很簡單的東西。

貼個範例程式碼吧,但跟以上的代碼無關。

(function(){
//擷取跨域資料
window.onmessage = function(e){
var url = "http://yangzebo.com/demo/noforget/test.php?msg=" + e.data;
//Ajax
var xhr = getXHR();
if(xhr){
xhr.open("GET",url,true);
xhr.onreadystatechange = changeHandle;
xhr.send(null);
}else{
alert("不支援Ajax");
}
function changeHandle(){//返回處理
if(xhr.readyState == 4){
var parentwin = window.parent;
parentwin.postMessage(xhr.responseText,"*");//跨域發送資料
}
}
function getXHR(){//擷取XMLHttpRequest
var xhr_temp;
if(window.XMLHttpRequest){
xhr_temp = new XMLHttpRequest();
}else if(window.ActiveXObject){
xhr_temp = new ActiveXObject("Microsoft.XMLHTTP");
}else{
xhr_temp = null;
}
return xhr_temp;
}
};
})();

  然後給個不好看的Demo。

有興趣代碼請求啥的自個用開發人員工具看吧,“zebo男”是從資料庫讀出來的,“my msg”是sendAndReceive.html發給test.php的Ajax請求的參數,通過test.php和iframeforAjax.html回傳到sendAndReceive.html。

3. 提示

要擷取iframe的contentWindow才能調用postMessage。

postMessage一定要在iframe載入完成之後調用才可以正常運行。(這個耗了我好長時間)

最後要感謝Joe哥的提示和給我偷用伺服器來測試的hulin小妹妹。:D

[原帖]:http://yangzebo.com/blog/?p=208

相關文章

聯繫我們

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