久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      html5服務(wù)器推送的詳細(xì)介紹

      在各種BS架構(gòu)的應(yīng)用程序中,往往都希望服務(wù)端能夠主動(dòng)地向客戶(hù)端推送各種消息,以達(dá)到類(lèi)似于郵件、消息、待辦事項(xiàng)等通知。

      往BS架構(gòu)本身存在的問(wèn)題就是,服務(wù)器一直采用的是一問(wèn)一答的機(jī)制。這就意味著如果客戶(hù)端不主動(dòng)地向服務(wù)器發(fā)送消息,服務(wù)器就無(wú)法得知如何給客戶(hù)端推送消息。

      隨著HTML、瀏覽器等各項(xiàng)技術(shù)、標(biāo)準(zhǔn)的發(fā)展,依次生成了不同的手段與方法能夠?qū)崿F(xiàn)服務(wù)端主動(dòng)推送消息,它們分別是:AJAX,Comet,ServerSent以及WebSocket。

      本篇文章將對(duì)上述提及到的各種技術(shù)手段進(jìn)行直白化的解釋。

      AJAX

      正常的一個(gè)頁(yè)面在瀏覽器中是這樣工作的:

      用戶(hù)向給予瀏覽器一個(gè)需要訪(fǎng)問(wèn)的地址

      瀏覽器根據(jù)這個(gè)地址訪(fǎng)問(wèn)服務(wù)器,并與服務(wù)器之間創(chuàng)建一個(gè)TCP連接(HTTP請(qǐng)求)

      服務(wù)器根據(jù)這個(gè)地址和一些其它數(shù)據(jù),組建一段HTML文本,將寫(xiě)入TCP連接,然后關(guān)閉連接

      瀏覽器得到了來(lái)自服務(wù)器的HTML文本,解析并呈現(xiàn)了瀏覽器上給用戶(hù)瀏覽

      此時(shí),用戶(hù)點(diǎn)擊了網(wǎng)站上任何一個(gè)<a>或觸發(fā)任何一個(gè)<form>提交時(shí):

      瀏覽器根據(jù)form的參數(shù)或者a的參數(shù),作為訪(fǎng)問(wèn)的地址

      與服務(wù)器創(chuàng)建TCP連接

      服務(wù)器組建HTML文本,然后關(guān)閉連接

      瀏覽器將當(dāng)前顯示的頁(yè)面摧毀,并按照新的HTML文本呈現(xiàn)一個(gè)新的頁(yè)面給用戶(hù)

      我們不難發(fā)現(xiàn)的是整個(gè)過(guò)程中間,一旦建立了一個(gè)連接,頁(yè)面就無(wú)法再維護(hù)住了。整個(gè)過(guò)程看上去有點(diǎn)強(qiáng)買(mǎi)強(qiáng)賣(mài),也許我只要一杯新的可樂(lè),但你非要給我一整個(gè)套餐組合。

      此時(shí)我們可以了解一下XmlHttpRequest組件,這個(gè)組件提供我們手動(dòng)創(chuàng)建一個(gè)HTTP請(qǐng)求,發(fā)送我們想要的數(shù)據(jù),服務(wù)器也可以只返回我們想要的結(jié)果,最大的好處是,當(dāng)我們收到服務(wù)器的響應(yīng)時(shí),原來(lái)的頁(yè)面沒(méi)有被摧毀。這就好比,我喊一句"我的咖啡喝完了,我要續(xù)杯",然后服務(wù)員就拿了一杯咖啡過(guò)來(lái),而不是會(huì)把我沒(méi)吃完的套餐全部倒掉。

      當(dāng)我們利用AJAX實(shí)現(xiàn)服務(wù)器推送時(shí),其實(shí)質(zhì)是客戶(hù)端不停地向服務(wù)器詢(xún)問(wèn)"有沒(méi)有給我的消息呀?",然后服務(wù)器回答"有"或"沒(méi)有"來(lái)達(dá)到的實(shí)現(xiàn)效果。它的實(shí)現(xiàn)方法也很簡(jiǎn)單,利用jQuery框架封裝好的AJAX調(diào)用也很方便:

      function getMessage(fn) {      $.ajax({          url: "Handler.ashx", //一個(gè)能夠提供消息的頁(yè)面          dataType: "text",    //響應(yīng)類(lèi)型,可以是JSON,XML等其它類(lèi)型          type: "get",         //HTTP請(qǐng)求類(lèi)型,還可以是post          success: function (d, s) {              fn(d);           //得到了正常的響應(yīng)時(shí),利用回調(diào)函數(shù)通知外部        },          complete: function (x, s) {              setTimeout(function () {                  getMessage(fn);              }, 5000);       //無(wú)論響應(yīng)成功或失敗,在若干秒后再詢(xún)問(wèn)一次服務(wù)器        }      });  }

      通過(guò)上面的代碼,可以每隔5秒詢(xún)問(wèn)一次服務(wù)器是否有需要處理的消息,通過(guò)這種方式可以達(dá)到推送的效果,但是會(huì)存在一個(gè)問(wèn)題:

      間隔時(shí)間越快,推送的及時(shí)性越好,服務(wù)器的消費(fèi)越大;

      間隔時(shí)間越慢,推送的及時(shí)性越低,服務(wù)器的消費(fèi)越小。

      而且嚴(yán)格地來(lái)說(shuō),這種實(shí)際方式,并不是真正意義上的服務(wù)器主動(dòng)推送消息,但由于早期技術(shù)手段缺乏,所以AJAX輪循成為了一種很普遍的手段。

      下面對(duì)服務(wù)器推送事件的規(guī)范進(jìn)行具體的說(shuō)明。

      規(guī)范

      Server-sent Events 規(guī)范是 HTML 5 規(guī)范的一個(gè)組成部分,具體的規(guī)范文檔見(jiàn)參考資源。該規(guī)范比較簡(jiǎn)單,主要由兩個(gè)部分組成:第一個(gè)部分是服務(wù)器端與瀏覽器端之間的通訊協(xié)議,第二部分則是在瀏覽器端可供 JavaScript 使用的 EventSource 對(duì)象。通訊協(xié)議是基于純文本的簡(jiǎn)單協(xié)議。服務(wù)器端的響應(yīng)的內(nèi)容類(lèi)型是“text/event-stream”。響應(yīng)文本的內(nèi)容可以看成是一個(gè)事件流,由不同的事件所組成。每個(gè)事件由類(lèi)型和數(shù)據(jù)兩部分組成,同時(shí)每個(gè)事件可以有一個(gè)可選的標(biāo)識(shí)符。不同事件的內(nèi)容之間通過(guò)僅包含回車(chē)符和換行符的空行(“rn”)來(lái)分隔。每個(gè)事件的數(shù)據(jù)可能由多行組成。代碼清單 1 給出了服務(wù)器端響應(yīng)的示例。

      服務(wù)器端響應(yīng)的示例

      data: first event    data: second event  id: 100    event: myevent  data: third event  id: 101    : this is a comment  data: fourth event  data: fourth event continue

      如代碼清單 1 所示,每個(gè)事件之間通過(guò)空行來(lái)分隔。對(duì)于每一行來(lái)說(shuō),冒號(hào)(“:”)前面表示的是該行的類(lèi)型,冒號(hào)后面則是對(duì)應(yīng)的值??赡艿念?lèi)型包括:

      1. 類(lèi)型為空白,表示該行是注釋?zhuān)瑫?huì)在處理時(shí)被忽略。

      2. 類(lèi)型為 data,表示該行包含的是數(shù)據(jù)。以 data 開(kāi)頭的行可以出現(xiàn)多次。所有這些行都是該事件的數(shù)據(jù)。

      3. 類(lèi)型為 event,表示該行用來(lái)聲明事件的類(lèi)型。瀏覽器在收到數(shù)據(jù)時(shí),會(huì)產(chǎn)生對(duì)應(yīng)類(lèi)型的事件。

      4. 類(lèi)型為 id,表示該行用來(lái)聲明事件的標(biāo)識(shí)符。

      5. 類(lèi)型為 retry,表示該行用來(lái)聲明瀏覽器在連接斷開(kāi)之后進(jìn)行再次連接之前的等待時(shí)間。

      在上面代碼中,第一個(gè)事件只包含數(shù)據(jù)“first event”,會(huì)產(chǎn)生默認(rèn)的事件;第二個(gè)事件的標(biāo)識(shí)符是 100,數(shù)據(jù)為“second event”;第三個(gè)事件會(huì)產(chǎn)生類(lèi)型為“myevent”的事件;最后一個(gè)事件的數(shù)據(jù)為“fourth eventnfourth event continue”。當(dāng)有多行數(shù)據(jù)時(shí),實(shí)際的數(shù)據(jù)由每行數(shù)據(jù)以換行符連接而成。

      如果服務(wù)器端返回的數(shù)據(jù)中包含了事件的標(biāo)識(shí)符,瀏覽器會(huì)記錄最近一次接收到的事件的標(biāo)識(shí)符。如果與服務(wù)器端的連接中斷,當(dāng)瀏覽器端再次進(jìn)行連接時(shí),會(huì)通過(guò) HTTP 頭“Last-Event-ID”來(lái)聲明最后一次接收到的事件的標(biāo)識(shí)符。服務(wù)器端可以通過(guò)瀏覽器端發(fā)送的事件標(biāo)識(shí)符來(lái)確定從哪個(gè)事件開(kāi)始來(lái)繼續(xù)連接。

      對(duì)于服務(wù)器端返回的響應(yīng),瀏覽器端需要在 JavaScript 中使用 EventSource 對(duì)象來(lái)進(jìn)行處理。EventSource 使用的是標(biāo)準(zhǔn)的事件監(jiān)聽(tīng)器方式,只需要在對(duì)象上添加相應(yīng)的事件處理方法即可。EventSource 提供了三個(gè)標(biāo)準(zhǔn)事件,如表 1 所示。

      表 1. EventSource 對(duì)象提供的標(biāo)準(zhǔn)事件

      名稱(chēng)

      說(shuō)明

      事件處理方法

      open

      當(dāng)成功與服務(wù)器建立連接時(shí)產(chǎn)生

      onopen

      message

      當(dāng)收到服務(wù)器發(fā)送的事件時(shí)產(chǎn)生

      onmessage

      error

      當(dāng)出現(xiàn)錯(cuò)誤時(shí)產(chǎn)生

      onerror

      如之前所述,服務(wù)器端可以返回自定義類(lèi)型的事件。對(duì)于這些事件,可以使用 addEventListener 方法來(lái)添加相應(yīng)的事件處理方法。代碼清單 2 給出了 EventSource 對(duì)象的使用示例。

      EventSource 對(duì)象的使用示例

      var es = new EventSource('events');  es.onmessage = function(e) {      console.log(e.data);  };    es.addEventListener('myevent', function(e) {      console.log(e.data);  });

      如上所示,在指定 URL 創(chuàng)建出 EventSource 對(duì)象之后,可以通過(guò) onmessage 和 addEventListener 方法來(lái)添加事件處理方法。當(dāng)服務(wù)器端有新的事件產(chǎn)生,相應(yīng)的事件處理方法會(huì)被調(diào)用。EventSource 對(duì)象的 onmessage 屬性的作用類(lèi)似于 addEventListener( ‘ message ’ ),不過(guò) onmessage 屬性只支持一個(gè)事件處理方法。在介紹完服務(wù)器推送事件的規(guī)范內(nèi)容之后,下面介紹服務(wù)器端的實(shí)現(xiàn)。

      服務(wù)器端和瀏覽器端實(shí)現(xiàn)

      從上一節(jié)中對(duì)通訊協(xié)議的描述可以看出,服務(wù)器端推送事件是一個(gè)比較簡(jiǎn)單的協(xié)議。服務(wù)器端的實(shí)現(xiàn)也相對(duì)比較簡(jiǎn)單,只需要按照協(xié)議規(guī)定的格式,返回響應(yīng)內(nèi)容即可。在開(kāi)源社區(qū)可以找到各種不同的服務(wù)器端技術(shù)相對(duì)應(yīng)的實(shí)現(xiàn)。自己開(kāi)發(fā)的難度也不大。本文使用 Java 作為服務(wù)器端的實(shí)現(xiàn)語(yǔ)言。相應(yīng)的實(shí)現(xiàn)基于開(kāi)源的 jetty-eventsource-servlet 項(xiàng)目,見(jiàn)參考資源。下面通過(guò)一個(gè)具體的示例來(lái)說(shuō)明如何使用 jetty-eventsource-servlet 項(xiàng)目。示例用來(lái)模擬一個(gè)物體在某個(gè)限定空間中的隨機(jī)移動(dòng)。該物體從一個(gè)隨機(jī)位置開(kāi)始,然后從上、下、左和右四個(gè)方向中隨機(jī)選擇一個(gè)方向,并在該方向上移動(dòng)隨機(jī)的距離。服務(wù)器端不斷改變?cè)撐矬w的位置,并把位置信息推送給瀏覽器,由瀏覽器來(lái)顯示。

      服務(wù)器端實(shí)現(xiàn)

      服務(wù)器端的實(shí)現(xiàn)由兩部分組成:一部分是用來(lái)產(chǎn)生數(shù)據(jù)的 org.eclipse.jetty.servlets.EventSource 接口的實(shí)現(xiàn),另一部分是作為瀏覽器訪(fǎng)問(wèn)端點(diǎn)的繼承自 org.eclipse.jetty.servlets.EventSourceServlet 類(lèi)的 servlet 實(shí)現(xiàn)。下面代碼給出了 EventSource 接口的實(shí)現(xiàn)類(lèi)。

      EventSource 接口的實(shí)現(xiàn)類(lèi) MovementEventSource

       public class MovementEventSource implements EventSource {      private int width = 800;   private int height = 600;   private int stepMax = 5;   private int x = 0;   private int y = 0;   private Random random = new Random();   private Logger logger = Logger.getLogger(getClass().getName());      public MovementEventSource(int width, int height, int stepMax) {    this.width = width;    this.height = height;    this.stepMax = stepMax;    this.x = random.nextInt(width);    this.y = random.nextInt(height);   }     @Override   public void onOpen(Emitter emitter) throws IOException {    query(emitter); //開(kāi)始生成位置信息   }     @Override   public void onResume(Emitter emitter, String lastEventId)     throws IOException {    updatePosition(lastEventId); //更新起始位置    query(emitter);  //開(kāi)始生成位置信息   }      //根據(jù)Last-Event-Id來(lái)更新起始位置   private void updatePosition(String id) {    if (id != null) {     String[] pos = id.split(",");     if (pos.length > 1) {      int xPos = -1, yPos = -1;      try {       xPos = Integer.parseInt(pos[0], 10);       yPos = Integer.parseInt(pos[1], 10);      } catch (NumberFormatException e) {             }      if (isValidMove(xPos, yPos)) {       x = xPos;       y = yPos;      }     }    }   }      private void query(Emitter emitter) throws IOException {    emitter.comment("Start sending movement information.");    while(true) {     emitter.comment("");     move(); //移動(dòng)位置     String id = String.format("%s,%s", x, y);     emitter.id(id); //根據(jù)位置生成事件標(biāo)識(shí)符     emitter.data(id); //發(fā)送位置信息數(shù)據(jù)     try {      Thread.sleep(2000);     } catch (InterruptedException e) {      logger.log(Level.WARNING,                  "Movement query thread interrupted. Close the connection.", e);      break;     }    }    emitter.close(); //當(dāng)循環(huán)終止時(shí),關(guān)閉連接   }     @Override   public void onClose() {       }      //獲取下一個(gè)合法的移動(dòng)位置   private void move() {    while (true) {     int[] move = getMove();     int xNext = x + move[0];     int yNext = y + move[1];     if (isValidMove(xNext, yNext)) {      x = xNext;      y = yNext;      break;     }    }   }     //判斷當(dāng)前的移動(dòng)位置是否合法   private boolean isValidMove(int x, int y) {    return x >= 0 && x <= width && y >=0 && y <= height;   }      //隨機(jī)生成下一個(gè)移動(dòng)位置   private int[] getMove() {    int[] xDir = new int[] {-1, 0, 1, 0};    int[] yDir = new int[] {0, -1, 0, 1};    int dir = random.nextInt(4);    return new int[] {xDir[dir] * random.nextInt(stepMax),        yDir[dir] * random.nextInt(stepMax)};   }  }

      類(lèi) MovementEventSource 需要實(shí)現(xiàn) EventSource 接口的 onOpen、onResume 和 onClose 方法,其中 onOpen 方法在瀏覽器端的連接打開(kāi)的時(shí)候被調(diào)用,onResume 方法在瀏覽器端重新建立連接時(shí)被調(diào)用,onClose 方法則在瀏覽器關(guān)閉連接的時(shí)候被調(diào)用。onOpen 和 onResume 方法都有一個(gè) EventSource.Emitter 接口類(lèi)型的參數(shù),可以用來(lái)發(fā)送數(shù)據(jù)。EventSource.Emitter 接口中包含的方法包括 data、event、comment、id 和 close 等,分別對(duì)應(yīng)于通訊協(xié)議中各種不同類(lèi)型的事件。而 onResume 方法還額外包含一個(gè)參數(shù) lastEventId,表示通過(guò) Last-Event-ID 頭發(fā)送過(guò)來(lái)的最近一次事件的標(biāo)識(shí)符。

      MovementEventSource 類(lèi)中事件生成的主要邏輯在 query 方法中。該方法中包含一個(gè)無(wú)限循環(huán),每隔 2 秒鐘改變一次位置,同時(shí)把更新之后的位置通過(guò) EventSource.Emitter 接口的 data 方法發(fā)送給瀏覽器端。每個(gè)事件都有對(duì)應(yīng)的標(biāo)識(shí)符,而標(biāo)識(shí)符的值就是位置本身。如果連接斷開(kāi)之后,瀏覽器重新進(jìn)行連接,可以從上一次的位置開(kāi)始繼續(xù)移動(dòng)該物體。

      與 MovementEventSource 類(lèi)對(duì)應(yīng)的 servlet 實(shí)現(xiàn)比較簡(jiǎn)單,只需要繼承自 EventSourceServlet 類(lèi)并覆寫(xiě) newEventSource 方法即可。在 newEventSource 方法的實(shí)現(xiàn)中,需要返回一個(gè) MovementEventSource 類(lèi)的對(duì)象,如下所示。每當(dāng)瀏覽器端建立連接時(shí),該 servlet 會(huì)創(chuàng)建一個(gè)新的 MovementEventSource 類(lèi)的對(duì)象來(lái)處理該請(qǐng)求。

      servlet 實(shí)現(xiàn)類(lèi) MovementServlet

       public class MovementServlet extends EventSourceServlet {      @Override    protected EventSource newEventSource(HttpServletRequest request,    String clientId) {    return new MovementEventSource(800, 600, 20);    }    }

      在服務(wù)器端實(shí)現(xiàn)中,需要注意的是要添加相應(yīng)的 servlet 過(guò)濾器支持。這是 jetty-eventsource-servlet 項(xiàng)目所依賴(lài)的 Jetty Continuations 框架的要求,否則的話(huà)會(huì)出現(xiàn)錯(cuò)誤。添加過(guò)濾器的方式是在 web.xml 文件中添加代碼如下所示的配置內(nèi)容。

      Jetty Continuations 所需 servlet 過(guò)濾器的配置

       <filter>       <filter-name>continuation</filter-name>       <filter-class>org.eclipse.jetty.continuation.ContinuationFilter</filter-class>    </filter>    <filter-mapping>       <filter-name>continuation</filter-name>       <url-pattern>/sse/*</url-pattern>    </filter-mapping>

      瀏覽器端實(shí)現(xiàn)

      瀏覽器端的實(shí)現(xiàn)也比較簡(jiǎn)單,只需要?jiǎng)?chuàng)建出 EventSource 對(duì)象,并添加相應(yīng)的事件處理方法即可。下面代碼給出了相應(yīng)的實(shí)現(xiàn)。在頁(yè)面中使用一個(gè)方塊表示物體。當(dāng)接收到新的事件時(shí),根據(jù)事件數(shù)據(jù)中給出的坐標(biāo)信息,更新方塊在頁(yè)面上的位置。

      瀏覽器端的實(shí)現(xiàn)代碼

       var es = new EventSource('sse/movement');    es.addEventListener('message', function(e) {        var pos = e.data.split(','), x = pos[0], y = pos[1];        $('#box').css({            left : x + 'px',            top : y + 'px'            });        });

      在介紹完基本的服務(wù)器端和瀏覽器端實(shí)現(xiàn)之后,下面介紹比較重要的 IE 的支持。

      IE 支持

      使用瀏覽器原生的 EventSource 對(duì)象的一個(gè)比較大的問(wèn)題是 IE 并不提供支持。為了在 IE 上提供同樣的支持,一般有兩種辦法。第一種辦法是在其他瀏覽器上使用原生 EventSource 對(duì)象,而在 IE 上則使用簡(jiǎn)易輪詢(xún)或 COMET 技術(shù)來(lái)實(shí)現(xiàn);另外一種做法是使用 polyfill 技術(shù),即使用第三方提供的 JavaScript 庫(kù)來(lái)屏蔽瀏覽器的不同。本文使用的是 polyfill 技術(shù),只需要在頁(yè)面中加載第三方 JavaScript 庫(kù)即可。應(yīng)用本身的瀏覽器端代碼并不需要進(jìn)行改動(dòng)。一般推薦使用第二種做法,因?yàn)檫@樣的話(huà),在服務(wù)器端只需要使用一種實(shí)現(xiàn)技術(shù)即可。

      在 IE 上提供類(lèi)似原生 EventSource 對(duì)象的實(shí)現(xiàn)并不簡(jiǎn)單。理論上來(lái)說(shuō),只需要通過(guò) XMLHttpRequest 對(duì)象來(lái)獲取服務(wù)器端的響應(yīng)內(nèi)容,并通過(guò)文本解析,就可以提取出相應(yīng)的事件,并觸發(fā)對(duì)應(yīng)的事件處理方法。不過(guò)問(wèn)題在于 IE 上的 XMLHttpRequest 對(duì)象并不支持獲取部分的響應(yīng)內(nèi)容。只有在響應(yīng)完成之后,才能獲取其內(nèi)容。由于服務(wù)器端推送事件使用的是一個(gè)長(zhǎng)連接。當(dāng)連接一直處于打開(kāi)狀態(tài)時(shí),通過(guò) XMLHttpRequest 對(duì)象并不能獲取響應(yīng)的內(nèi)容,也就無(wú)法觸發(fā)對(duì)應(yīng)的事件。更具體的來(lái)說(shuō),當(dāng) XMLHttpRequest 對(duì)象的 readyState 為 3(READYSTATE_INTERACTIVE)時(shí),其 responseText 屬性是無(wú)法獲取的。

      為了解決 IE 上 XMLHttpRequest 對(duì)象的問(wèn)題,就需要使用 IE 8 中引入的 XDomainRequest 對(duì)象。XDomainRequest 對(duì)象的作用是發(fā)出跨域的 AJAX 請(qǐng)求。XDomainRequest 對(duì)象提供了 onprogress 事件。當(dāng) onprogress 事件發(fā)生時(shí),可以通過(guò) responseText 屬性來(lái)獲取到響應(yīng)的部分內(nèi)容。這是 XDomainRequest 對(duì)象和 XMLHttpRequest 對(duì)象的最大不同,也是使用 XDomainRequest 對(duì)象來(lái)實(shí)現(xiàn)類(lèi)似原生 EventSource 對(duì)象的基礎(chǔ)。在使用 XDomainRequest 對(duì)象打開(kāi)與服務(wù)器端的連接之后,當(dāng)服務(wù)器端有新的數(shù)據(jù)產(chǎn)生時(shí),可以通過(guò) XDomainRequest 對(duì)象的 onprogress 事件的處理方法來(lái)進(jìn)行處理,對(duì)接收到的數(shù)據(jù)進(jìn)行解析,根據(jù)數(shù)據(jù)的內(nèi)容觸發(fā)相應(yīng)的事件。

      不過(guò)由于 XDomainRequest 對(duì)象本來(lái)的目的是發(fā)出跨域 AJAX 請(qǐng)求,考慮到跨域訪(fǎng)問(wèn)的安全性問(wèn)題,XDomainRequest 對(duì)象在使用時(shí)的限制也比較嚴(yán)格。這些限制會(huì)影響到其作為 EventSource 對(duì)象的實(shí)現(xiàn)方式。具體的限制和解決辦法如下所示:

      1. 服務(wù)器端的響應(yīng)需要包含 Access-Control-Allow-Origin 頭,用來(lái)聲明允許從哪些域訪(fǎng)問(wèn)該 URL?!?”表示允許來(lái)自任何域的訪(fǎng)問(wèn),不推薦使用該值。一般使用與當(dāng)前應(yīng)用相同的域,限制只允許來(lái)自當(dāng)前域的訪(fǎng)問(wèn)。

      2. XDomainRequest 對(duì)象發(fā)出的請(qǐng)求不能包含自定義的 HTTP 頭,這就限制了不能使用 Last-Event-ID 頭來(lái)聲明瀏覽器端最近一次接收到的事件的標(biāo)識(shí)符。只能通過(guò) HTTP 請(qǐng)求的其他方式來(lái)傳遞該標(biāo)識(shí)符,如 GET 請(qǐng)求的參數(shù)或 POST 請(qǐng)求的內(nèi)容體。

      3. XDomainRequest 對(duì)象的請(qǐng)求的內(nèi)容類(lèi)型(Content-Type)只能是“text/plain”。這就意味著,當(dāng)使用 POST 請(qǐng)求時(shí),服務(wù)器端使用的框架,如 servlet,不會(huì)對(duì) POST 請(qǐng)求的內(nèi)容進(jìn)行自動(dòng)解析,無(wú)法使用 HttpServletRequest 類(lèi)的 getParameter 方法來(lái)獲取 POST 請(qǐng)求的內(nèi)容。只能在服務(wù)器端對(duì)原始的請(qǐng)求內(nèi)容進(jìn)行解析,獲取到其中的參數(shù)的值。

      4. XDomainRequest 對(duì)象發(fā)出的請(qǐng)求中不包含任何與用戶(hù)認(rèn)證相關(guān)的信息,包括 cookie 等。這就意味著,如果服務(wù)器端需要認(rèn)證,則需要通過(guò) HTTP 請(qǐng)求的其他方式來(lái)傳遞用戶(hù)的認(rèn)證信息,比如 session 的 ID 等。

      由于 XDomainRequest 對(duì)象的這些限制,服務(wù)器端的實(shí)現(xiàn)也需要作出相應(yīng)的改動(dòng)。這些改動(dòng)包括返回 Access-Control-Allow-Origin 頭;對(duì)于瀏覽器端發(fā)送的“text/plain”類(lèi)型的參數(shù)進(jìn)行解析;處理請(qǐng)求中包含的用戶(hù)認(rèn)證相關(guān)的信息。

      本文的示例使用的 polyfill 庫(kù)是 GitHub 上的 Yaffle 開(kāi)發(fā)的 EventSource 項(xiàng)目,具體的地址見(jiàn)參考資源。在使用該 polyfill 庫(kù),并對(duì)服務(wù)器端的實(shí)現(xiàn)進(jìn)行修改之后,就可以在 IE 8 及以上的瀏覽器中使用服務(wù)器推送事件。如果需要支持 IE 7,則只能使用簡(jiǎn)易輪詢(xún)或 COMET 技術(shù)。本文的示例代碼見(jiàn)參考資源。

      小結(jié)

      如果需要從服務(wù)器端推送數(shù)據(jù)給瀏覽器,可以使用的基于 HTML 5 規(guī)范標(biāo)準(zhǔn)的技術(shù)包括 WebSocket 和服務(wù)器推送事件。開(kāi)發(fā)人員可以根據(jù)應(yīng)用的具體需求來(lái)選擇合適的技術(shù)。如果只是需要從服務(wù)器端推送數(shù)據(jù),服務(wù)器推送事件的規(guī)范更加簡(jiǎn)單,實(shí)現(xiàn)起來(lái)更容易。本文對(duì)服務(wù)器推送事件的規(guī)范內(nèi)容、服務(wù)器端和瀏覽器端的實(shí)現(xiàn)都進(jìn)行了詳細(xì)的介紹,對(duì)如何支持 IE 瀏覽器也進(jìn)行了具體的分析。

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)