1. 程式人生 > >Javascript跨域訪問解決方案

Javascript跨域訪問解決方案

原文地址:http://blog.csdn.net/lovingprince/article/details/2954675

由於安全方面的考慮, Javascript 被限制了跨域訪問的能力,但是有時候我們希望能夠做一些合理的跨域訪問的事情,那麼怎麼辦呢?

這裡分兩類情況:


         一、基於同一父域的子域之間頁面的訪問 
                 參見如下 3 個 domain 域:

1 、 taobao.com
          2 、 jipiao.taobao.com
          3 、 promotion.taobao.com

它們有相同的父域   taobao.com


         二、基於不同父域頁面之間的訪問 
                 參見如下 3 個 domain 域:

1 、 taobao.com
             2 、 baidu.com

3 、 sina.com.cn

     它們具有不同的父域。

解決它們之間跨域的方案:

<!--[if !supportLists]-->①<!--[endif]-->伺服器 Proxy:   域 A 的頁面 JS 需要訪問域 B 下的連結獲取資料,該方案在域 A 的伺服器端建立一個Proxy 程式 ( 可能是 ASP 、 servlet 等任何服務端程式 ) ,域 A 的頁面 JS 直接呼叫本域下的 Proxy 程式, proxy 程式負責將請求傳送給域 B下的連結並獲取到資料,最後再通過 Proxy 將資料返回給頁面 JS 使用。

經過的訪問流程就是: 域 A 下 JS-- à 域 A 下 Proxy--- à 域 B 下的連結

例子:

第一步:

[javascript] view plaincopyprint?
  1.    <mce:script type=”text/javascript”><!--  
  2.     Var sUrl=” http://Jipiao.taobao.com/proxy.do ”; // 本域下代理地址   
  3. var callback =  
  4. {  
  5.    success: function(res) {   alert(res.responseText);   },   
  6.    failure: function
    (res) {  alert(‘failure’);},   
  7.    argument:{}   
  8. }   
  9.   YAHOO.util.Connect.asyncRequest(’GET’, sUrl, callback, null);     
  10. // --></mce:script>   

第二步:

Proxy 程式 ( 這裡假定是一個 servlet) :

[java] view plaincopyprint?
  1. Public class Proxy extends …….{   
  2. ..doGet(……..){   
  3. HttpClient  client=……;   
  4. GetMethod get= new   GetMethod(" www.baidu.com/xxxxx.do ") ;// 訪問域 B 的連結   
  5. int statusCode = client.executeMethod( get );   
  6. if (statusCode != HttpStatus.SC_OK) {   
  7. byte[] responseBody = get.getResponseBody();  
  8. String res=new String(responseBody);  
  9. Httpresponse.getWriter().write(res);//  
  10. 將資料返回給域  
  11. A  
  12.     }   
  13. }   
  14. }   
  

<!--[if !supportLists]-->② <!--[endif]-->  Script 標籤 : 域 A 頁面 http://Jipiao.taobao.com/test.htm 的 head 中寫一個空的 Script 標籤

[xhtml] view plaincopyprint?
  1. <html>   
  2.   <head>   
  3.   <mce:script id=”remoteScript” type=”text/javascript” src="””" mce_src="””" /><!--  
  4.   <head>   
  5.   <body>   
  6. <script type=”text/javascript” >   
  7.   Var remoteScript=document.getElementById(‘remoteScript’);   
  8.   remoteScript.src=” www.baidu.com/xxxxx.do”;// 域 B 的連結   
  9.   alert(remote.test);// 使用域 B 返回的 JSON 資料   
  10.   alert(f[0]);   
  11. // --></mce:script>   
  12.   </body>   
  13. </html>   

注意:這種方案要求域 B 返回的資料必須是合法的 JSON 格式或者如 JS 檔案的格式。

域 B 返回的資料格式如下:

[javascript] view plaincopyprint?
  1. Var remote={test:’hello’};   
  2. Var f=[‘2,1];   
  3. {“test”:"hello","arrays":[2,1]}  

對於基於同一父域的子域之間頁面的訪問這一類情況,還有第三種方式: 
    ③ 隱藏 iframe: 即域 A jipiao.taobao.com/yyyy.htm 的頁面上寫一個隱藏的 iframe ,

[xhtml] view plaincopyprint?
  1. <html>   
  2.   <head>   
  3. <head>   
  4.   <body>   
  5. <mce:script type=”text/javascript” ><!--  
  6.   Document.domain=”taobao.com”;   
  7.   Var remoteHtml=document.getElementById(“remoteHtml”);   
  8. remoteHtml.src=”promotion.taobao.com/xxxx.htm”;// 這裡訪問域 B 的連結   
  9. var document=remoteHtml.ContentDocument;   
  10.   …// 這裡就可以使用 document 來操作域 B 中頁面 xxx.htm 的資料了   
  11. // --></mce:script>   
  12. <iframe id=”remoteHtml” src="””" mce_src="””"   style="”diapay:none”/" mce_style="”diapay:none”/">   
  13.   </body>   
  14. </html>   
  

這裡 promotion.taobao.com/xxxx.htm 頁面也需要設定 document.domain="taobao.com" , 這種方法才能奏效。之所以這種 iframe 的方法不適合不同父域之間的跨域,是因為設定 document.domain 只能設定為自己的父域,而不是能設定為其他域,例如 :jiapiao.taobao.com 只能設定document.domain=”taobao.com” ,而不是是 document.domain=”baidu.com”

優缺點比較:

  這裡列舉的三種方案各有優缺點:

  Proxy 方案優點是可以適用用於幾乎所有的跨域訪問,而且只需要要一個域中進行開發,另一個域可以提供任何型別格式的資料。缺點是這種方案經過了中間 Proxy ,所以延遲可能稍微大一點,並且會加重本域伺服器的負荷,開發工作量也稍微大一點。

  Script 標籤的方案可以說是非常簡單的,不用幾行程式碼就搞定了事,不過它對返回的資料格式要求有點嚴格,只能是 Json 格式資料 , 如果是其他格式的資料,那麼這種方法就無能為力了。

隱藏 iframe 方式也很簡單,它可以處理任何返回的資料格式,但它只適用在具有同一個父域下的跨域請求上,並且要求其他域得配合開發,即需要設定 document.domain

================

補充:Script標籤標籤方法最好要求服務端返回的json需要有控制代碼,即 如 json={...} 什麼的。因為客戶端需要使用這個控制代碼來引用。如果沒有,客戶端JS只有採用 var json=eval(jsonStr)方式來執行,效率不是很高。還有一種形式就是客戶端傳入要回調的方法。例如 xxxx.do?callbackApi=ca

服務端接收到callbackApi引數後,將json包裝在ca中,如:ca({.....});

客戶端定義回撥函式就可以訪問了。

   function ca(json){

         .......

   }

不論如何,這種方法對於服務端都有一定耦合。