跨域問題實踐總結!下( [HTML5] postMessage+服務器端(反向代理服務器+CORS Cross-Origin Resource Sharing))

 

4. [HTML5] postMessage

問題:javascript

對於跨域問題,研究了一下html5的postMessage,寫了代碼測試了一下,感受html5新功能就是好用啊。
此文僅使用html5的新特性postMessage,演示其執行過程和效果:html

方法解釋:
postMessage()方法容許來自不一樣源的腳本採用異步方式進行有限的通訊,能夠實現跨文本檔、多窗口、跨域消息傳遞。
postMessage(data,origin)方法接受兩個參數:
1.data:你須要傳遞的消息,消息傳遞的格式有必定要求:參數能夠是JavaScript的任意基本類型或可複製的對象,然而並非全部瀏覽器都作到了這點兒,部分瀏覽器只能處理字符串參數,因此建議直接傳遞string類型參數。json格式使用JSON.stringify()方法對對象參數序列化,在低版本IE中引用json2.js能夠實現相似效果。
2.origin:該參數指明目標窗口的源。postMessage()方法只會將message傳遞給指定窗口,也能夠設置爲"*",表示能夠傳遞給任意窗口。html5

原理:java

1.個人頁面是parent.html,接收我發送的消息並按照要求返回消息的頁面是child.html;git

2.兩個頁面放在同一個文件夾內;github

3.parent.html發送postMessage消息給child.html,child.html收到消息後經過source.postMessage返回所需信息!apache

 

具體過程以下:json

個人頁面是parent.html:api

複製代碼
<html>
<div>
    <iframe id="child" src="./child.html"></iframe>
</div>
<script type="text/javascript">
    window.addEventListener('message',function(e){
        alert("msg from child:" + e.data);
    });
    window.onload=function(){//頁面加載完即向iframe發送消息
        //var tmp = document.getElementById("child");
        //tmp.postMessage('hello babi','*');  //此處tmp沒有postMessage方法,類型錯誤。
        //alert(tmp); //這是object HTMLIFrameElement類型
        //alert(window.frames[0]);  //這是object Window類型
        //以上方式不可行,只有window類型才能調用postMessage方法!
        window.frames[0].postMessage('hello babi','*');
    }
</script>
</html>
複製代碼

中間的文字全都來自child.html!跨域

 

咱們看看接收消息頁面child.html:

parent頁面向child頁面發送了消息,那麼在child頁面上如何接收消息呢,監聽window的message事件就能夠

複製代碼
<html>
<p id="ll1">I'm child</p>
<p id="ll2">I'm child</p>
<p id="ll3">I'm child</p>
<p id="ll4">I'm child</p>
<script type="text/javascript">
    window.addEventListener('message',function(e){//接收信息後返回信息!
        alert("msg from parent:" + e.data);
        e.source.postMessage('Hello papi', "*");
    });
</script>
</html>
複製代碼

這樣咱們就能夠接收任何窗口傳遞來的消息了!

咱們運行一下:

這樣就實現了跨域、跨窗口消息傳遞

服務器端的跨域方法

1、反向代理服務器

基礎思想很簡單,將你的服務器配置成 須要跨域獲取的資源的 反向代理服務器。

也就是說,將其餘域名的資源映射到你本身的域名之下,這樣瀏覽器就認爲他們是同源的。

用你們鍾愛的 Apache2 來舉個例子:

首先啓用兩個模塊 proxy 和 proxy_http 來開啓代理功能:

sudo a2enmod proxy
sudo a2enmod proxy_http

而後在配置文件裏面寫入:

ProxyPass "/foo" "http://foo.example.com/bar" ProxyPassReverse "/foo" "http://foo.example.com/bar"
  • ProxyPass: 遠程服務器在本地服務器的映射。(上面的例子將 http://foo.example.com/bar 映射爲 /foo

  • ProxyPassReverse: 配置 Apache2 在 HTTP 跳轉時調整 LocationContent-Location 和 URI headers 的值,防止反向代理被繞開。

重啓 Apache2:

sudo service apache2 restart

大功告成,這樣咱們請求 /foo 就會獲得 http://foo.example.com/bar 的內容了。

這種方法其實不太經常使用,機智的讀者就會發現,每個資源都要到本身的服務器配置,每次配置都還要重啓。

2、CORS

Cross-Origin Resource Sharing 是 W3C 推出的一種跨站資源獲取的機制。

首先咱們來看一下瀏覽器的支持狀況:

Chrome Firefox (Gecko) Internet Explorer Opera Safari
4 3.5 8 & 9(XDomainRequest), 10 12 4

移動端的瀏覽器對這種方法的支持比較完善。如今咱們看到了,若是不須要兼容 IE六、7的話,就可使用這種方法。


這種跨域方案主要的思想是:服務器 在響應頭中設置相應的選項,瀏覽器若是支持這種方法的話就會將這種跨站資源請求視爲合法,進而獲取資源。

能夠設置的響應頭信息:

Access-Control-Allow-Origin

Access-Control-Allow-Origin: <origin> | *

origin: 被容許跨域訪問這個資源的網站,* 表明所有網站。瀏覽器會檢測這個參數,若是符合要求,纔會去獲取資源。

舉個例子,容許 http://jasonkid.github.io/fezone 來跨域訪問這個資源:

Access-Control-Allow-Origin: http://jasonkid.github.io/fezone

Access-Control-Allow-Credentials

Access-Control-Allow-Credentials: true | false

表示是否容許瀏覽器攜帶 Cookie 來訪問這個資源。
這個屬性要和 XMLHttpRequest 的 withCredentials 屬性來配合使用。

var xhr = new XMLHttpRequest(); var url = 'http://foo.other/resources/credentialed-content/'; if(xhr) { xhr.open('GET', url, true); xhr.withCredentials = true; // 設置帶有 Cookie 的資源請求 xhr.onreadystatechange = handler; xhr.send(); }

可以成功使用帶有 Cookie 的資源請求須要知足如下幾個條件:

  • XMLHttpRequest 對象中指定了 withCredentials = true

  • 服務器響應頭中 Access-Control-Allow-Credentials: true

  • 服務器響應頭中 Access-Control-Allow-Origin 不能爲 *


如下選項主要是安全性配置的問題,主要是服務器的配置問題了,就不展開介紹了:

  • Access-Control-Expose-Headers

  • Access-Control-Allow-Methods

  • Access-Control-Allow-Headers

相關文章
相關標籤/搜索