風之力

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            19 Posts :: 2 Stories :: 18 Comments :: 0 Trackbacks

          一般情形下,為安全起見,瀏覽器不允許你在客戶端通過XMLHttpRequest訪問別的域(參考連接1,2),即使是同一域的子域也不行,譬如www.joycode.com?到 blog.joycode.com。(你可以通過某些設置來訪問子域,但因為這方法不是很通行,所有就不考慮了,但如果你感興趣,參考連接2。)

          但很明顯,在不少情形下,訪問別的網站,獲取別的網站的信息/服務是非常有用的,特別是在這個Web 2.0時代。

          常用的跨站訪問的方法有3種(參考連接3,4):

          1. 在同一域的服務器端建立一個代理,瀏覽器向該代理網址發送請求,然后該代理向其他域的網址發請求,在獲取回復后,或作處理或按原樣發回到瀏覽器
          2. 使用按需(On-Demand) Javascript 腳本。在頁面內動態生成新的<script>,將其src屬性指向別的網站的網址,這個網址返回的內容必須是合法的Javascript腳本,常用的是JSON消息。
          3. 使用IFRAME。在頁面內嵌或動態生成指向別的網站的IFRAME,然后這2個網頁間可以通過改變對方的anchor hash fragment來傳輸消息。改變一個網頁的anchor hash fragment并不會使瀏覽器重新裝載網頁,所以一個網頁的狀態得以保持,而網頁本身則可以通過一個計時器(timer)來察覺自己anchor hash的變化,從而相應改變自己的狀態(參考這個帖子中提及的Nikhil Kothari的歷史控件中的方法)。 Julien Couvreur在他的《Cross-document messaging hack》里描述了一個更復雜的應用情形,
            "....
            For example, if you have page A containing an iframe B in a different domain,then B can create a new iframe and load it with a url in the same domain as A. The url that is loaded doesn't generate a request to the server if it is properly cached and only the fragment identifier is used to pass changing information. Page A can now get the DOM handle on the new iframe and successfully retrieve the information transmitted in the url by B...." (大體這樣,網頁A包含了一個IFRAME B,B的網頁來自一個不同的域。然后B頁可以生成一個IFRAME C,把它指向與網頁A同域的某個地址,因為是A與C同域,網頁A可以訪問C里的信息,反之亦然。)

          ASP.NET AJAX擴展(即Atlas)提供了一個橋(bridge)機制讓你在服務器端配置來訪問別的網站,并同時支持POX和SOAP這2種協議。想了解其中細節,請參考Atlas文檔里的《Building Mash-ups with "Atlas"》。當然你完全可以自己建立一個web service,通過它來訪問其他網站并返回信息。

          據說,Atlas中的 IFrameExecutor 可以實現跨域的調用,我按照MSDN博客Federal Developer Weblog的這篇帖子《Calling web services hosted outside of your application with “Atlas”》上的步驟試了一下,但在Windows 2003 Server SP1上得到卻是“Access is denied”的錯誤信息。然后我下載了該文中的項目,試驗的結果仍舊是“Access is denied”。也許需要改動一些瀏覽器中的什么設置才能成功,但這不是我的目的,我需要一個在普通設置下都能成功的例子。

          按需(On-Demand) Javascript腳本的實現是很簡單的,譬如我有這樣一個網頁,(想測試的話,需要改動其中的網址)

          <html>
          <head>
          <script language="javascript" type="text/javascript">
          function loadContent()
          {
          var s=document.createElement('SCRIPT');
          s.src='
          document.body.appendChild(s);
          }

          function setDivContent(v)
          {
          var dv = document.getElementById("dv");
          dv.innerHTML = v;
          }
          </script>
          </head>
          <body>
          <div id="dv"></div>

          <input type="button" value="Click Me" onclick="loadContent()">
          </body>
          </html>

          其中的www.anotherdomain.com/TestCrossJS.aspx是這樣的,

          <script language="C#" runat="server">
          void Page_Load(object sender, EventArgs e)
          {
          ? string f = Request.QueryString["f"];
          ? Response.Clear();
          ? Response.ContentType = "application/x-javascript";
          ? Response.Write(String.Format(@"
          ?????????????????? {0}('{1}');",?
          ???????????????????f,
          ?????????????????? DateTime.Now));
          ? Response.End();
          }
          </script>

          點擊“Click Me”按鈕,生成一個新的script tag,下載對應的 Javascript 腳本,結束時回調其中的setDivContent(),從而更新網頁上一個div的內容。

          IFRAME的方法好像很流行,除了dojo工具包支持外,據微軟的Dare Obasanjo說(參考連接9),Windows Live Contacts Gadget使用了這個方法來獲取Hotmail的address book。最近,Plaxo公司的開發人員 Joseph Smarr在七月的OSCON 2006會議上作了一個題為《Cross-site Ajax: Challenges and Techniques for Building Rich Web 2.0 Mashups》的講座[來源:Kevin Yank--OSCON 2006: Cross-site Ajax],他們將這個方法做成了一個平臺,允許合作伙伴間合作,他們開發的方案叫“The JavaScript Wormhole(蟲洞)”,據說準備將其推廣為一個標準。他講座的PPT可以在這里下載,里面對這個方案做了說明,非常值得看一下。

          現在將IFRAME的方法簡單示范如下:

          1. http://domain1/TestCross.html:

          <html>
          <head>
          <script language="javascript" type="text/javascript">
          var url = "http://domain2/TestCross.html"
          var oldHash = null;
          var timer = null;

          function getHash()
          {
          var hash = window.location.hash;
          if ((hash.length >= 1) && (hash.charAt(0) == '#'))
          {
          hash = hash.substring(1);
          }

          return hash;
          }
          function sendRequest()
          {
          var d = document;
          var t = d.getElementById('request');
          var f = d.getElementById('alienFrame');
          f.src = url + "#" + t.value + "<br/>" + new Date();
          }

          function setDivHtml(v)
          {
          var d = document;
          var dv = d.getElementById('response');
          dv.innerHTML = v;
          }

          function idle()
          {
          var newHash = getHash();

          if (newHash != oldHash)
          {
          setDivHtml(newHash);
          oldHash = newHash;
          }

          timer = window.setTimeout(idle, 100);
          }

          function window.onload()
          {
          timer = window.setTimeout(idle, 100);
          }
          </script>
          </head>
          <body>

          請求:<input type="text" id="request"> <input type="button" value="發送" onclick="sendRequest()" /><br/>
          回復:<div id="response"></div>

          <iframe id="alienFrame" src="http://domain2/TestCross.html"></iframe>

          </body>
          </html>

          2. http://domain2/TestCross.html:

          <html>
          <head>
          <script language="javascript" type="text/javascript">
          var url = "http://domain1/TestCross.html"
          var oldHash = null;
          var timer = null;

          function getHash()
          {
          var hash = window.location.hash;
          if ((hash.length >= 1) && (hash.charAt(0) == '#'))
          {
          hash = hash.substring(1);
          }

          return hash;
          }
          function sendRequest()
          {
          var d = document;
          var t = d.getElementById('request');
          var f = parent;
          //alert(f.document); //試著去掉這個注釋,你會得到“Access is denied”
          f.location.href = url + "#" + t.value + "<br/>" + new Date();
          }

          function setDivHtml(v)
          {
          var d = document;
          var dv = d.getElementById('response');
          dv.innerHTML = v;
          }

          function idle()
          {
          var newHash = getHash();

          if (newHash != oldHash)
          {
          setDivHtml(newHash);
          oldHash = newHash;
          }

          timer = window.setTimeout(idle, 100);
          }

          function window.onload()
          {
          timer = window.setTimeout(idle, 100);
          }
          </script>
          </head>
          <body>

          請求:<input type="text" id="request"> <input type="button" value="發送" onclick="sendRequest()" /><br/>
          回復:<div id="response"></div>

          </body>
          </html>

          兩個網頁基本相同,第一個網頁內嵌一個IFRAME,在點擊“發送”按鈕后,會將文本框里的內容通過hash fragment傳給IFRAME。點擊IFRAME里的“發送”按鈕后,它會將文本框里的內容通過hash fragment傳給父窗口。因為是只改動了hash fragment,瀏覽器不會重新load網頁內容,這里使用了一個計時器來檢測URL變化,如果變化了,就更新其中一個div的內容 。

          這個方法是不是個安全漏洞?考慮到微軟的Windows Live都在使用這個方法,估計不是,。這個方法是不是很安全?考慮到這個方法只有在2個網站協作的情形才能成功,安全問題好像不是很大,除非其中涉及的網站本身有XSS的問題。

          【參考連接】

          1. Security Considerations: Dynamic HTML
          http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/sec_dhtml.asp

          2. About Cross-Frame Scripting and Security
          http://msdn.microsoft.com/library/default.asp?url=/workshop/author/om/xframe_scripting_security.asp

          3. Cross-Domain Proxy
          http://ajaxpatterns.org/Cross-Domain_Proxy

          4. Cross Domain XMLHttpRequest using an IFrame Proxy
          http://manual.dojotoolkit.org/WikiHome/DojoDotBook/Book75

          5. Back Button Support for Atlas UpdatePanels
          http://www.nikhilk.net/BackButtonSupport.aspx

          6. Cross-document messaging hack
          http://blog.monstuff.com/archives/000304.html

          7. Building Mash-ups with "Atlas"
          http://atlas.asp.net/docs/Walkthroughs/DevScenarios/bridge.aspx

          8. Calling web services hosted outside of your application with “Atlas”
          http://blogs.msdn.com/federaldev/archive/2006/07/31/684229.aspx

          http://www.federaldeveloper.com/Shared%20Documents/Presentations%20by%20Marc%20Schweigert/CallAtlasWebServiceInDifferentProject.zip

          9. AJAX Tip: Passing Messages Between iframes
          http://www.25hoursaday.com/weblog/PermaLink.aspx?guid=3b03cf9d-b589-4838-806e-64efcc0a1a15

          10. OSCON Cross-site Ajax Slides
          http://blog.plaxo.com/archives/2006/07/oscon_crosssite.html

          http://www.plaxo.com/css/api/Joseph-Smarr-Plaxo-OSCON-2006.ppt

          11. OSCON 2006: Cross-site Ajax
          http://www.sitepoint.com/blogs/2006/07/28/oscon-2006-cross-site-ajax/

          posted on 2006-10-16 16:38 風之力 閱讀(697) 評論(0)  編輯  收藏 所屬分類: ajax

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 四子王旗| 周宁县| 勐海县| 定安县| 扎鲁特旗| 凤冈县| 德阳市| 海南省| 江孜县| 九寨沟县| 汨罗市| 长垣县| 古蔺县| 利津县| 东阳市| 吉木萨尔县| 崇信县| 蒙阴县| 精河县| 绥化市| 察隅县| 阿鲁科尔沁旗| 改则县| 阿拉善左旗| 天水市| 如东县| 临桂县| 仲巴县| 神池县| 伊春市| 临澧县| 罗田县| 佛山市| 兰溪市| 绥芬河市| 财经| 嘉黎县| 全南县| 突泉县| 九寨沟县| 乐陵市|