聶永的博客

          記錄工作/學習的點點滴滴。

          Servlet 3.0筆記之異步請求Comet推送XMLHttpRequest示范

          說實話,各個瀏覽器對XMLHttpRequest內置對象請求異步連接(或者稱呼為長連接)的支持不一而足,除了Firefox,Safari,IE8等,其它的要么不支持,要么有缺陷。總之,單純依靠XHR(XMLHttpRequest的簡稱)來調用長連接,不靠譜。
          XMLHttpRequest對象在標準情況下,在請求長連接情況下,readyState = 3時處于一直監聽情況,但各大主流瀏覽器內的支持相關情況不盡相同:
          1. IE(IE6-IE7),只有在請求的內容不再發生變化時以及 readyState = 4 的時候才會獲取到返回的responseText內容,因此不支持長連接。
          2. IE8:以XDomainRequest取代ActiveXObject對象,也算是一個進步,但在服務器端有邀請,必須在頭部設置 Access-Control-Allow-Origin值,若不知道客戶端調用JS所處的域名,設置成星號,通用即可。
          3. Opera:貌似只有在readyState=3時才會觸發一次onreadystatechange函數,不支持長連接。
          4. Firefox 3.6 和Safari 4:默認支持XMLHttpRequest Streaming。
          5. Chrome 4.1版本:只有在請求內容不再發生變化才會達到readyState=2狀態,所以支持情況不太好。
          要檢測各個瀏覽器對XMLHttpRequest的支持請求,這里有一個好的去處:
           Streaming Test page 
          以上內容,翻譯摘選自:COMET Streaming in Internet Explore 
          一個客戶端訂閱頁面:
           page
          頁面代碼:
          <html>
          <head>
          <title>comet XHR測試</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("當前瀏覽器不支持創建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);
          }
          };
          // 經測試:
          // IE8,Safayi完美支持onprogress事件(可以不需要onreadystatechange事件);
          // Chrome也支持,在后臺數據推送到時,會調用其方法,但無法得到responseText值;除非(長連接關閉)
          // 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>
          當然后臺需要一個內容發布的頁面:
          write2
          后臺處理的代碼和上篇隱藏IFrame服務器推送部分較為類似相似:
          /**
          * 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();

          // 若當前輸出內容較少情況下,需要產生大約2KB的垃圾數據,諸如下面產生一些空格
          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();
          // 設置成長久鏈接
          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平臺下,需要預先生成一些大小為2K的垃圾數據,諸如一些空格。

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

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

          公告

          所有文章皆為原創,若轉載請標明出處,謝謝~

          新浪微博,歡迎關注:

          導航

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

          統計

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個人收藏

          最新隨筆

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 加查县| 隆子县| 池州市| 伊春市| 会东县| 康保县| 枣庄市| 师宗县| 高雄市| 交口县| 盘锦市| 沭阳县| 田林县| 东乡县| 西充县| 浪卡子县| 山丹县| 乃东县| 商城县| 安阳县| 榆社县| 宝坻区| 沙坪坝区| 盐边县| 南京市| 怀来县| 河源市| 通海县| 惠州市| 溧水县| 包头市| 花莲市| 新竹县| 肇州县| 西藏| 吉木乃县| 柳江县| 屯门区| 万山特区| 绥化市| 靖远县|