聶永的博客

          記錄工作/學(xué)習(xí)的點(diǎn)點(diǎn)滴滴。

          Servlet 3.0筆記之異步請(qǐng)求Comet推送XMLHttpRequest示范

          說實(shí)話,各個(gè)瀏覽器對(duì)XMLHttpRequest內(nèi)置對(duì)象請(qǐng)求異步連接(或者稱呼為長連接)的支持不一而足,除了Firefox,Safari,IE8等,其它的要么不支持,要么有缺陷。總之,單純依靠XHR(XMLHttpRequest的簡(jiǎn)稱)來調(diào)用長連接,不靠譜。
          XMLHttpRequest對(duì)象在標(biāo)準(zhǔn)情況下,在請(qǐng)求長連接情況下,readyState = 3時(shí)處于一直監(jiān)聽情況,但各大主流瀏覽器內(nèi)的支持相關(guān)情況不盡相同:
          1. IE(IE6-IE7),只有在請(qǐng)求的內(nèi)容不再發(fā)生變化時(shí)以及 readyState = 4 的時(shí)候才會(huì)獲取到返回的responseText內(nèi)容,因此不支持長連接。
          2. IE8:以XDomainRequest取代ActiveXObject對(duì)象,也算是一個(gè)進(jìn)步,但在服務(wù)器端有邀請(qǐng),必須在頭部設(shè)置 Access-Control-Allow-Origin值,若不知道客戶端調(diào)用JS所處的域名,設(shè)置成星號(hào),通用即可。
          3. Opera:貌似只有在readyState=3時(shí)才會(huì)觸發(fā)一次onreadystatechange函數(shù),不支持長連接。
          4. Firefox 3.6 和Safari 4:默認(rèn)支持XMLHttpRequest Streaming。
          5. Chrome 4.1版本:只有在請(qǐng)求內(nèi)容不再發(fā)生變化才會(huì)達(dá)到readyState=2狀態(tài),所以支持情況不太好。
          要檢測(cè)各個(gè)瀏覽器對(duì)XMLHttpRequest的支持請(qǐng)求,這里有一個(gè)好的去處:
           Streaming Test page 
          以上內(nèi)容,翻譯摘選自:COMET Streaming in Internet Explore 
          一個(gè)客戶端訂閱頁面:
           page
          頁面代碼:
          <html>
          <head>
          <title>comet XHR測(cè)試</title>
          <meta http-equiv="X-UA-Compatible" content="IE=8" />
          <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
          <meta name="author" content="yongboy@gmail.com" />
          <meta name="keywords" content="servlet3, comet, ajax" />
          <meta name="description" content="" />
          <link type="text/css" rel="stylesheet" href="css/main.css" />
          </head>
          <body style="margin: 0; overflow: hidden" onload="">
          <div id="showDiv" class="inputStyle"></div>
          <script>
          function showMsg(msg) {
          document.getElementById("showDiv").innerHTML = msg;
          }
          function doXHR() {
          var xhr = null;
          // 在IE8下面,window.XMLHttpRequest = true,因此需要window.XDomainRequest放在第一位置
          if (window.XDomainRequest) {
          xhr = new XDomainRequest();
          } else if (window.XMLHttpRequest) {
          xhr = new XMLHttpRequest();
          } else if (window.ActiveXObject) {
          var aVersions = [ "Msxml2.XMLHttp.5.0", "Msxml2.XMLHttp.4.0",
          "Msxml2.XMLHttp.3.0", "Msxml2.XMLHttp", "Microsoft.XMLHttp" ];
          for ( var i = 0; i < aVersions.length; i++) {
          try {
          xhr = new ActiveXObject(aVersions[i]);
          break;
          } catch (e) {
          }
          }
          }

          if (xhr == null) {
          showMsg("當(dāng)前瀏覽器不支持創(chuàng)建XMLHttpRequest !");
          return;
          }

          try {
          xhr.onload = function() {
          showMsg(xhr.responseText);
          };
          xhr.onerror = function() {
          showMsg("XMLHttpRequest Fatal Error.");
          };
          xhr.onreadystatechange = function() {
          try {
          if (xhr.readyState > 2) {
          showMsg(xhr.responseText);
          }
          } catch (e) {
          showMsg("XMLHttpRequest Exception: " + e);
          }
          };
          // 經(jīng)測(cè)試:
          // IE8,Safayi完美支持onprogress事件(可以不需要onreadystatechange事件);
          // Chrome也支持,在后臺(tái)數(shù)據(jù)推送到時(shí),會(huì)調(diào)用其方法,但無法得到responseText值;除非(長連接關(guān)閉)
          // Firefox 3.6 也支持,但得到返回值有些BUG
          xhr.onprogress = function() {
          showMsg(xhr.responseText);
          };
          xhr.open("GET", "getnew?" + Math.random(), true);
          xhr.send(null);
          } catch (e) {
          showMsg("XMLHttpRequest Exception: " + e);
          }
          }
          if (window.addEventListener) {
          window.addEventListener("load", doXHR, false);
          } else if (window.attachEvent) {
          window.attachEvent("onload", doXHR);
          }
          </script>
          </body>
          </html>
          當(dāng)然后臺(tái)需要一個(gè)內(nèi)容發(fā)布的頁面:
          write2
          后臺(tái)處理的代碼和上篇隱藏IFrame服務(wù)器推送部分較為類似相似:
          /**
          * XHR獲取最新信息
          *
          * @author yongboy
          * @date 2011-1-10
          * @version 1.0
          */
          @WebServlet(urlPatterns = "/getnew", asyncSupported = true)
          public class GetNewBlogPosts extends HttpServlet {
          private static final long serialVersionUID = 5656988888865656L;
          private static final Log log = LogFactory.getLog(GetNewBlogPosts.class);

          protected void doGet(HttpServletRequest request,
          HttpServletResponse response) throws ServletException, IOException {
          response.setHeader("Cache-Control", "private");
          response.setHeader("Pragma", "no-cache");
          response.setHeader("Connection", "Keep-Alive");
          response.setHeader("Proxy-Connection", "Keep-Alive");
          response.setHeader("Access-Control-Allow-Origin", "*");
          response.setContentType("text/html;charset=UTF-8");
          response.setCharacterEncoding("UTF-8");
          PrintWriter writer = response.getWriter();

          // 若當(dāng)前輸出內(nèi)容較少情況下,需要產(chǎn)生大約2KB的垃圾數(shù)據(jù),諸如下面產(chǎn)生一些空格
          for (int i = 0; i < 10; i++) {
          writer.print(" ");
          }

          writer.println("<div class='logDiv,clear'>waiting for ......</div>");
          writer.flush();

          final AsyncContext ac = request.startAsync();
          // 設(shè)置成長久鏈接
          ac.setTimeout(10 * 60 * 1000);
          ac.addListener(new AsyncListener() {
          public void onComplete(AsyncEvent event) throws IOException {
          NewBlogXHRListener.ASYNC_XHR_QUEUE.remove(ac);
          }

          public void onTimeout(AsyncEvent event) throws IOException {
          NewBlogXHRListener.ASYNC_XHR_QUEUE.remove(ac);
          }

          public void onError(AsyncEvent event) throws IOException {
          NewBlogXHRListener.ASYNC_XHR_QUEUE.remove(ac);
          }

          public void onStartAsync(AsyncEvent event) throws IOException {
          log.info("now add the AsyncContext");
          }
          });

          NewBlogXHRListener.ASYNC_XHR_QUEUE.add(ac);
          }
          }
          不過多了兼容IE8的代碼部分:
          response.setHeader("Access-Control-Allow-Origin", "*");
          在IE8以及Chrome平臺(tái)下,需要預(yù)先生成一些大小為2K的垃圾數(shù)據(jù),諸如一些空格。

          單獨(dú)線程代碼和上篇隱藏IFrame服務(wù)器推送部分相似,這里不再貼出。
          經(jīng)測(cè)試:
          1. 在ubuntu 10.10系統(tǒng)下Chrome(版本號(hào)8.0.552.224),支持XHR Streaming,測(cè)試通過。
          2. 2.Firefox 3.6 下測(cè)試通過。
          3. Safari 5.0.3 測(cè)試通過。
          4. IE8測(cè)試通過。

          posted on 2011-01-13 10:20 nieyong 閱讀(2367) 評(píng)論(0)  編輯  收藏 所屬分類: Servlet3

          公告

          所有文章皆為原創(chuàng),若轉(zhuǎn)載請(qǐng)標(biāo)明出處,謝謝~

          新浪微博,歡迎關(guān)注:

          導(dǎo)航

          <2011年1月>
          2627282930311
          2345678
          9101112131415
          16171819202122
          23242526272829
          303112345

          統(tǒng)計(jì)

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個(gè)人收藏

          最新隨筆

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 越西县| 台中县| 合水县| 新郑市| 肇东市| 陇川县| 海安县| 岑溪市| 天气| 罗甸县| 甘肃省| 绥化市| 安泽县| 永嘉县| 宁安市| 友谊县| 东城区| 泗洪县| 平阳县| 新源县| 斗六市| 团风县| 会昌县| 灵丘县| 五家渠市| 调兵山市| 包头市| 德昌县| 页游| 普兰县| 德清县| 康乐县| 锡林浩特市| 云浮市| 屯留县| 海口市| 奇台县| 微博| 河间市| 章丘市| 江山市|