weidagang2046的專欄

          物格而后知致
          隨筆 - 8, 文章 - 409, 評論 - 101, 引用 - 0
          數(shù)據(jù)加載中……

          服務器端可控情形的Javascript跨域訪問解決方法

          2006-12-5

          ?

          我在最近的一個 web 項目中為了實現(xiàn) bookmark 功能碰到了 javascript 跨域訪問的問題。起初,在 google 上搜的很多解決方案并不適用于我的情形,只在有一篇文章中提到的遠程加載 javascript 方法從理論上看到了解決的希望。但可惜作者只是一筆帶過,并未用例子詳細說明,所以不得不摸索了一陣才把這個問題搞定。在此,希望通過本文為同樣被這個問題困擾的朋友們提供一個解決方法作為參考。如有錯誤,歡迎指正!

          ?

          Bookmark 是目前許多 web2.0 網(wǎng)站 (http://del.icio.us/, www.diigo.com 等)都提供的熱門 feature 。它能將互聯(lián)網(wǎng)上自己喜歡的網(wǎng)頁收藏到 Bookmark 服務器上。本文要解決的問題就發(fā)生在用戶提交網(wǎng)頁 URL (還包括 Tag, Notes 等)給 Bookmark 服務器時。

          ?

          關(guān)于 URL 的提交至少可以有三種方式:

          ?

          1.?????? 登陸 Bookmark 服務器的提交頁面,將要收藏的 URL 通過該頁面提交給服務器。

          2.?????? 安裝瀏覽器插件,通過插件將 URL 提交給服務器。

          3.?????? Bookmark 服務器動態(tài)加載 javascript 小工具到當前頁面,通過它來完成提交工作。(參考 diigo 的例子,收藏一個網(wǎng)頁鏈接到瀏覽器收藏夾,鏈接的 URL 是一段 javascript 代碼,它會從服務器加載一段 javascript 注入當前網(wǎng)頁)

          ?

          第一種方式開發(fā)起來最簡單,但對用戶來講比較麻煩,每次都需要先登陸 Bookmark 服務器才能完成提交;第二種方式我并不熟悉插件開發(fā),而且用戶也不喜歡太多的插件堆滿自己的瀏覽器;第三種方式開發(fā)難度小,又避免了每次登陸服務器的麻煩,所以我最終采用了它。

          ?

          上面講的第三種方式中動態(tài)加載的 javascript 小工具除了需要生成 UI 供用戶填寫信息( URL , tag , notes 等),當用戶點擊提交的時候,還要完成與服務器通信的功能。在沒有跨域訪問經(jīng)驗的情況下,最先想到的當然是 ajax !但很快就會發(fā)現(xiàn)根本行不通。

          ?

          跨域訪問,簡單來說就是 A 網(wǎng)站的 javascript 代碼試圖訪問 B 網(wǎng)站,包括提交內(nèi)容和獲取內(nèi)容。由于安全原因,跨域訪問是被各大瀏覽器所默認禁止的。寫過跨域訪問 ajax 的朋友相信都遇到過被告知“沒有權(quán)限”的情況。通過 XMLHttp 來發(fā)送數(shù)據(jù)給 Bookmark 服務器的嘗試失敗了。于是,看到網(wǎng)上的一些資料,我又開始嘗試用 javascript 小工具在用戶網(wǎng)頁動態(tài)創(chuàng)建一個隱藏的 iframe, iframe src 指向服務器的一個 servlet ,試圖通過調(diào)用 iframe 中提供的 javascript 來完成與服務器的通信。但不幸的是,用戶網(wǎng)頁中的 javascript 代碼訪問 iframe 也被瀏覽器歸為跨域訪問(特指 iframe src 指向其它網(wǎng)站的情形),嘗試再次失敗。

          ?

          最終,在一篇文章中看到,與 iframe 不同,如果 A 網(wǎng)站從 B 網(wǎng)站加載 javascript , A 網(wǎng)站可以自由的訪問該 javascript 的內(nèi)容,并不會被瀏覽器認為是跨域訪問。模仿剛才 iframe 的思路,當用戶點擊提交時,可以動態(tài)創(chuàng)建一個 javascript 對象,該對象的 src 指向 Bookmark 服務器的一個 servlet ,注意: URL Tag 、 Notes 、 User 、 Password 等信息被作為 src URL 參數(shù)傳給服務器。請看下面的代碼:

          ?

          var url = "http://localhost:8080/Deeryard/BookmarkServlet?" +

          ?????????? "url=" + url_source + "&" + "title=" + title + "&" +

          "tag=" + tag + "&" + "notes=" + notes + "&" + "user=" + user + "&" + "password=" + password;

          ?

          url = encodeURI(url);

          ???

          //Submit to server with a trick

          var js_obj = document.createElement( "script" );

          js_obj.type = "text/javascript" ;

          js_obj.setAttribute( "src" , url);

          ???

          //Get response from server by appending it to document

          document.body.appendChild(js_obj);

          ?

          上面例子中, js_obj.setArrribute() 將信息作為 src URL 參數(shù)提交給了 Bookmark servlet 。那么用戶又如何取得服務器的響應信息呢?答案就是最末一行代碼, servlet 的輸出必須是 javascript 代碼,它可以調(diào)用用戶網(wǎng)頁上的其他 javascript 函數(shù),以及操作 dom 對象。下面的 servlet 代碼生成了一個 javascript 函數(shù)調(diào)用:

          ?

          out.write("onServerResponse(INADEQUATE_INFORMATION);");

          ?

          document.body.appendChild(js_obj) 執(zhí)行后 onServerResponse( INADEQUATE_INFORMATION) 就會得到執(zhí)行,使客戶網(wǎng)頁響應服務器結(jié)果。這樣一個完整的通信過程就完成了。

          ?

          來總結(jié)一下這個案例,首先與很多跨域訪問的情形不同,本文提到的跨域訪問需要對服務器端進行控制,即讓服務器端 Servlet 來適應客戶端網(wǎng)頁 javascript 的需求;而其他一些常見的例子則對服務器端沒有控制能力,比如從其他網(wǎng)站抓內(nèi)容的小偷程序。另外,需要注意的是這種方法中實際用到了 get 方法來提交信息,從一些資料上看到, get 方法每次提交的信息不能超過 2k 。

          posted on 2006-12-05 22:48 weidagang2046 閱讀(9291) 評論(11)  編輯  收藏

          評論

          # re: 服務器端可控情形的Javascript跨域訪問解決方法  回復  更多評論   

          IBM developerWorks上面有個文章,里面詳細講了ajax的三種數(shù)據(jù)傳輸機制,你上面這個實例就是其中的第三種方法。
          教程文章地址:
          http://www-128.ibm.com/developerworks/cn/views/xml/tutorials.jsp?cv_doc_id=110100
          需要注冊個ID才能閱讀。
          2006-12-06 09:27 | xinheqishi

          # re: 服務器端可控情形的Javascript跨域訪問解決方法  回復  更多評論   

          我有個問題哦....
          比如,我第一次發(fā)送的時候創(chuàng)建一個script對象,然后在很斷的時間內(nèi)發(fā)送了第二次,也就是創(chuàng)建了第二個script對象.那天他就把第一個覆蓋了,第一個怎么辦??

          但我又不能創(chuàng)建很多個script對象,那樣很占資源,只能刪除一些對象,那樣就又可能刪除寫沒有反會的對象......

          我的前提是我則個情求比較頻繁..

          希望能解我之惑...
          email: zuan8888@gmail.com
          2007-01-13 14:37 | 剎那

          # re: 服務器端可控情形的Javascript跨域訪問解決方法  回復  更多評論   

          創(chuàng)建javascript對象的時候指定id屬性可以避免覆蓋;也可以按id查找對象來判斷是否已經(jīng)返回,如果找到的話就可以看情況刪除。關(guān)于id的維護問題辦法應該很多。比如,維護一個全局計數(shù)器。

          如果一定要同步的話(比如,第一次返回才能發(fā)第二次),建議看看javascript的wait()函數(shù)。

          ps: 我的javascript經(jīng)驗也不多,上面的建議還需要實踐檢驗。歡迎交流!
          2007-01-13 18:05 | weidagang2046

          # re: 服務器端可控情形的Javascript跨域訪問解決方法  回復  更多評論   

          請問這種方式下客戶端(瀏覽器端)和Bookmark servlet端之間的關(guān)系是不是和直接通過瀏覽器訪問Bookmark servlet的關(guān)系是一樣的? 因為我想用這個方法來解決一個問題,A網(wǎng)站(應該是相當于這里的Bookmark servlet)負責控制邏輯,B網(wǎng)站負責頁面的外觀顯示.
          客戶端從B網(wǎng)站進入之后, 要動態(tài)創(chuàng)建javascript對象,提交多次請求, 而我想維護多個請求之間的狀態(tài)關(guān)系;是否和直接通過瀏覽器訪問B網(wǎng)站一樣,維持session就OK了?

          希望能解我之惑....謝謝!
          2007-01-13 19:28 | sparklet

          # re: 服務器端可控情形的Javascript跨域訪問解決方法  回復  更多評論   

          因為Bookmark Servlet對javascript一無所知,只當成一般的網(wǎng)頁文本返回,所以我認為和一般瀏覽器的訪問沒有區(qū)別,用session維護狀態(tài)是完全可以的。
          2007-01-13 19:39 | weidagang2046

          # re: 服務器端可控情形的Javascript跨域訪問解決方法  回復  更多評論   

          可行 跨域真是雙刃劍
          2007-02-04 11:42 | 小雨

          # re: 服務器端可控情形的Javascript跨域訪問解決方法[未登錄]  回復  更多評論   

          可以MSN交流嗎?tangcaiyou@hotmail.com
          2007-06-17 10:45 | eric

          # re: 服務器端可控情形的Javascript跨域訪問解決方法  回復  更多評論   

          我嘗試了類似的代碼卻沒有成功。
          我在一個A網(wǎng)站的portlet中,iframe了一個B網(wǎng)站的jsp頁面,當點擊該jsp的某個鏈接后,我需要將一個參數(shù)傳送到A網(wǎng)站的某Servlet,可是沒有成功。
          代碼如下:
          site A的portlet:
          從IFrame中的頁面?zhèn)鱽淼膮?shù):<%=portlet_a_s%>
          <br/>
          <iframe width="300" height="300" src="http://siteB:7001/myWeb/B.jsp">
          </iframe>

          site B的jsp:
          <%@ page language="java" contentType="text/html;charset=UTF-8"%>
          <html>
          <head>
          <title>
          inner page
          </title>

          <script type="text/javascript">
          var lastScript;
          var h=document.getElementsByTagName("head")[0];

          function loadScript(url){
          var f=document.createElement("script");
          var d=new Date().getTime();
          f.type="text/javascript";
          f.id=d;
          f.src=url+'&date='+d;
          document.body.appendChild(f);
          if(lastScript&&g(lastScript))g(lastScript).parentNode.removeChild(g(lastScript));
          lastScript=d;
          }

          function g(x){
          return document.getElementById(x)
          }

          function onClickMeasureId(id){
          var hidden = g("hidden_input");
          hidden.value = id;
          var url = "http://siteA:7001/testWeb/portlets/portlet_a/PortletAServlet?id="+id;
          loadScript(url);
          }

          function onResponse(){
          alert("response");
          };
          </script>
          </head>
          <body>
          <a onclick="onClick('參數(shù)1')" href="#">參數(shù)1</a>
          </body>
          </html>

          siteA的Servlet:
          public class PorletAServlet extends HttpServlet
          {
          public void service(HttpServletRequest request,HttpServletResponse response){
          if ( request.getParameter("id") != null ){
          String id = request.getParameter("id").toString();
          HttpSession session = request.getSession();
          session.setAttribute("measure_id",request.getParameter("id") );
          try{
          response.setContentType("text/javascript");
          PrintWriter out = response.getWriter();
          out.write("onResponse();");
          }
          catch(Exception e){}
          }
          }
          }

          我執(zhí)行siteA的portal,在siteA的servlet中加入斷點,點擊portlet中iframe中的鏈接,發(fā)行servlet并沒有得到執(zhí)行。實在不知道為何不成功。

          不知道博主可否提供更加完整的例子?謝謝!
          2007-06-22 14:57 | liao

          # re: 服務器端可控情形的Javascript跨域訪問解決方法  回復  更多評論   

          @liao
          你的例子應該沒有大問題,應該調(diào)查servlet沒有得到執(zhí)行的原因??梢园製rl單獨拷貝出來,敲到瀏覽器的地址欄中試試看servlet能否執(zhí)行。我估計是url本身的問題,很可能沒有真正對應到那個servlet。
          2007-06-22 16:31 | weidagang2046@gmail.com

          # re: 服務器端可控情形的Javascript跨域訪問解決方法  回復  更多評論   

          你好我 我碰到了一個問題

          和你的說的類似

          希望你幫我看下

          多謝了 http://so.hr33.com/SearchResult.aspx?key=a&companyname=&zw=100&dq=100&sj=90&xl=10&jy=0&sex=2&age=0&yx=0&xz=0&hy=0&RCount=29&Page=1&type=1

          你點申請后點關(guān)閉就會提示 "拒絕訪問.."

          MAIL 我 colvinliu@qq.com
          2007-12-20 17:06 | colvinliu

          # re: 服務器端可控情形的Javascript跨域訪問解決方法  回復  更多評論   

          轉(zhuǎn)了一大圈 終于在這里找到了解決方法
          2010-04-22 11:21 | 唐兵

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


          網(wǎng)站導航:
           
          主站蜘蛛池模板: 邵阳市| 前郭尔| 景泰县| 封开县| 莱芜市| 囊谦县| 抚远县| 西平县| 喜德县| 盐池县| 阿鲁科尔沁旗| 浦北县| 天柱县| 象州县| 北碚区| 遂宁市| 内黄县| 林州市| 绥中县| 张家川| 阿尔山市| 娄烦县| 璧山县| 东丰县| 聂拉木县| 武汉市| 襄城县| 岚皋县| 黄山市| 筠连县| 高尔夫| 莱西市| 宜宾县| 湘西| 惠安县| 桂平市| 周至县| 乌鲁木齐县| 平邑县| 永康市| 颍上县|