HTTP 服務器消息推送之SSE

HTTP 服務器推送也稱 HTTP 流,是一種客戶端-服務器通訊模式,它將信息從 HTTP 服務器異步推送到客戶端,而無需客戶端請求。如今的 web 和 app 中,愈來愈多的場景使用這種通訊模式,好比實時的消息提醒,IM在線聊天,多人文檔協做等。之前實現這種相似的功能通常都是用ajax長輪詢,而如今咱們有了新的、更優雅的選擇 —— WebSocket 和 SSE。javascript

WebSocket是HTML5開始提供的一種在單個 TCP 鏈接上進行全雙工通信的協議。在WebSocket API中,瀏覽器和服務器只須要作一個握手的動做,而後,瀏覽器和服務器之間就造成了一條快速通道。二者之間就直接能夠數據互相傳送。瀏覽器經過 JavaScript 向服務器發出創建 WebSocket 鏈接的請求,鏈接創建之後,客戶端和服務器端就能夠經過 TCP 鏈接直接交換數據。當你獲取 Web Socket 鏈接後,你能夠經過 send() 方法來向服務器發送數據,並經過 onmessage 事件來接收服務器返回的數據。java

SSE 是 Server-Sent Events 的簡稱, 是一種服務器端到客戶端(瀏覽器)的單項消息推送。對應的瀏覽器端實現 Event Source 接口被制定爲HTML5 的一部分。不過如今IE不支持該技術。相比於 WebSocket,SSE 簡單不少,服務器端和客戶端工做量都要小不少、簡單不少,同時實現的功能也要有侷限。node

SSE&WebSocket

SSE與WebSocket有類似功能,都是用來創建瀏覽器與服務器之間的通訊渠道。二者的區別在於:

  • WebSocket是全雙工通道,能夠雙向通訊,功能更強;SSE是單向通道,只能服務器向瀏覽器端發送。
  • WebSocket是一個新的協議,須要服務器端支持;SSE則是部署在 HTTP協議之上的,現有的服務器軟件都支持。
  • SSE是一個輕量級協議,相對簡單;WebSocket是一種較重的協議,相對複雜。
  • SSE默認支持斷線重連,WebSocket則須要額外部署。
  • SSE支持自定義發送的數據類型。
  • SSE不支持CORS,參數url就是服務器網址,必須與當前網頁的網址在同一個網域(domain),並且協議和端口都必須相同。WebSocket支持

客戶端 EventSource

API

[Constructor(DOMString url, optional EventSourceInit eventSourceInitDict)]
interface EventSource : EventTarget {
  readonly attribute DOMString url;
  readonly attribute boolean withCredentials;

  // ready state
  const unsigned short CONNECTING = 0;
  const unsigned short OPEN = 1;
  const unsigned short CLOSED = 2;
  readonly attribute unsigned short readyState;

  // networking
  attribute EventHandler onopen;
  attribute EventHandler onmessage;
  attribute EventHandler onerror;

  void close();
};

dictionary EventSourceInit {
  boolean withCredentials = false;
};
複製代碼

基本用法

  1. 建立EventSource 實例
var source = new EventSource(url)
複製代碼
  1. 事件監聽
// 創建鏈接後,觸發`open` 事件
source.onopen = (event)=>{
  // ...
}

// 收到消息,觸發`message` 事件
source.onmessage = (event)=>{
  // ...
}

// 發生錯誤,觸發`error` 事件
source.onerror = (event)=>{
  // ...
}

// 自定義事件
source.addEventListener('eventName', event => {
  // ...
}, false)
複製代碼
  1. 關閉鏈接
source.close()
複製代碼

服務器端開發

響應頭設置

SSE的相應,須要設置以下的Http頭信息web

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
複製代碼

第一行,Content-Type 指定的 MIME 類型必須爲 text/event-streamajax

消息格式

SSE 推送的消息必須是UTF-8編碼的純文本。每次推送有若干個事件消息組成,每一個事件消息之間用兩個換行(\n\n)分割。每一個事件消息又有若干行組成,每行格式以鍵值對形式組成:express

[key]: value\n
複製代碼

key 有一下幾個值可取瀏覽器

  • data: 消息內容
  • event: 消息事件名稱,默認爲 message,瀏覽器能夠用 addEventListener()監聽該事件。
  • id: 消息編號。瀏覽器用lastEventId屬性讀取這個值。一旦鏈接斷線,瀏覽器會發送一個 HTTP 頭,裏面包含一個特殊的Last-Event-ID頭信息,將這個值發送回來,用來幫助服務器端重建鏈接。所以,這個頭信息能夠被視爲一種同步機制
  • retry: 瀏覽器從新發起鏈接的時間間隔。

示例

瀏覽器端代碼bash

// index.js
var source = new EventSource('/stream');
source.onmessage = function(event) {
  var message = event.data; 
  // do stuff based on received message 
};
複製代碼

服務器端代碼(nodejs)服務器

var express = require('express')
var fs = require('fs')
var app = express()

app.get('/stream', (req, res) => {
  res.writeHead(200, {
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache",
    "Connection": "keep-alive"
  });

  var interval = setInterval(function () {
    res.write("data: " + (new Date()) + "\n\n");
  }, 1000);

  req.connection.addListener("close", function () {
    clearInterval(interval);
  }, false);
})

app.listen(9999, (err) => {
  if (err) {
    console.log(err)
    return
  }
  console.log('listening on port 9999')
})
複製代碼

關注咱們

相關文章
相關標籤/搜索