風(fēng)之力

          BlogJava 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
            19 Posts :: 2 Stories :: 18 Comments :: 0 Trackbacks

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

          但很明顯,在不少情形下,訪問(wèn)別的網(wǎng)站,獲取別的網(wǎng)站的信息/服務(wù)是非常有用的,特別是在這個(gè)Web 2.0時(shí)代。

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

          1. 在同一域的服務(wù)器端建立一個(gè)代理,瀏覽器向該代理網(wǎng)址發(fā)送請(qǐng)求,然后該代理向其他域的網(wǎng)址發(fā)請(qǐng)求,在獲取回復(fù)后,或作處理或按原樣發(fā)回到瀏覽器
          2. 使用按需(On-Demand) Javascript 腳本。在頁(yè)面內(nèi)動(dòng)態(tài)生成新的<script>,將其src屬性指向別的網(wǎng)站的網(wǎng)址,這個(gè)網(wǎng)址返回的內(nèi)容必須是合法的Javascript腳本,常用的是JSON消息。
          3. 使用IFRAME。在頁(yè)面內(nèi)嵌或動(dòng)態(tài)生成指向別的網(wǎng)站的IFRAME,然后這2個(gè)網(wǎng)頁(yè)間可以通過(guò)改變對(duì)方的anchor hash fragment來(lái)傳輸消息。改變一個(gè)網(wǎng)頁(yè)的anchor hash fragment并不會(huì)使瀏覽器重新裝載網(wǎng)頁(yè),所以一個(gè)網(wǎng)頁(yè)的狀態(tài)得以保持,而網(wǎng)頁(yè)本身則可以通過(guò)一個(gè)計(jì)時(shí)器(timer)來(lái)察覺(jué)自己anchor hash的變化,從而相應(yīng)改變自己的狀態(tài)(參考這個(gè)帖子中提及的Nikhil Kothari的歷史控件中的方法)。 Julien Couvreur在他的《Cross-document messaging hack》里描述了一個(gè)更復(fù)雜的應(yīng)用情形,
            "....
            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...." (大體這樣,網(wǎng)頁(yè)A包含了一個(gè)IFRAME B,B的網(wǎng)頁(yè)來(lái)自一個(gè)不同的域。然后B頁(yè)可以生成一個(gè)IFRAME C,把它指向與網(wǎng)頁(yè)A同域的某個(gè)地址,因?yàn)槭茿與C同域,網(wǎng)頁(yè)A可以訪問(wèn)C里的信息,反之亦然。)

          ASP.NET AJAX擴(kuò)展(即Atlas)提供了一個(gè)橋(bridge)機(jī)制讓你在服務(wù)器端配置來(lái)訪問(wèn)別的網(wǎng)站,并同時(shí)支持POX和SOAP這2種協(xié)議。想了解其中細(xì)節(jié),請(qǐng)參考Atlas文檔里的《Building Mash-ups with "Atlas"》。當(dāng)然你完全可以自己建立一個(gè)web service,通過(guò)它來(lái)訪問(wèn)其他網(wǎng)站并返回信息。

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

          按需(On-Demand) Javascript腳本的實(shí)現(xiàn)是很簡(jiǎn)單的,譬如我有這樣一個(gè)網(wǎng)頁(yè),(想測(cè)試的話,需要改動(dòng)其中的網(wǎng)址)

          <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>

          點(diǎn)擊“Click Me”按鈕,生成一個(gè)新的script tag,下載對(duì)應(yīng)的 Javascript 腳本,結(jié)束時(shí)回調(diào)其中的setDivContent(),從而更新網(wǎng)頁(yè)上一個(gè)div的內(nèi)容。

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

          現(xiàn)在將IFRAME的方法簡(jiǎn)單示范如下:

          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>

          請(qǐng)求:<input type="text" id="request"> <input type="button" value="發(fā)送" onclick="sendRequest()" /><br/>
          回復(fù):<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); //試著去掉這個(gè)注釋,你會(huì)得到“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>

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

          </body>
          </html>

          兩個(gè)網(wǎng)頁(yè)基本相同,第一個(gè)網(wǎng)頁(yè)內(nèi)嵌一個(gè)IFRAME,在點(diǎn)擊“發(fā)送”按鈕后,會(huì)將文本框里的內(nèi)容通過(guò)hash fragment傳給IFRAME。點(diǎn)擊IFRAME里的“發(fā)送”按鈕后,它會(huì)將文本框里的內(nèi)容通過(guò)hash fragment傳給父窗口。因?yàn)槭侵桓膭?dòng)了hash fragment,瀏覽器不會(huì)重新load網(wǎng)頁(yè)內(nèi)容,這里使用了一個(gè)計(jì)時(shí)器來(lái)檢測(cè)URL變化,如果變化了,就更新其中一個(gè)div的內(nèi)容 。

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

          【參考連接】

          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 風(fēng)之力 閱讀(702) 評(píng)論(0)  編輯  收藏 所屬分類: ajax

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 河西区| 东方市| 衡南县| 花垣县| 霍林郭勒市| 阜南县| 丰台区| 岳普湖县| 江陵县| 报价| 奇台县| 平阳县| 临沂市| 丽水市| 涟源市| 黄石市| 宜兴市| 五原县| 阿荣旗| 视频| 柳州市| 莒南县| 上饶市| 长子县| 鄯善县| 龙里县| 仙游县| 五峰| 万安县| 阿尔山市| 马边| 海林市| 眉山市| 武定县| 沽源县| 丹阳市| 兖州市| 枣庄市| 双牌县| 松潘县| 太湖县|