Server-Sent Events 服務端發送事件

Server-Sent Events 服務端發送事件

大多數時候,網頁必須向服務器發送請求以接收新數據。服務端發送的事件,能夠將消息推送到網頁

什麼是SSE(Server-Sent Events)

本質上,SSE使用戶能夠訂閱實時數據流。
  每當此數據流更新時,用戶均可以實時看到新事件。
  若是你知道Long-Polling或Web Socket那麼你可能以爲它沒什麼大不了

SSE vs Web-Socket

Websocket是服務器之間的雙向通訊形式。
  它一般用於創建聊天室或多人視頻遊戲,由於這些應用程序場景須要服務器和客戶端之間的持續通訊。
  你能夠將SSE視爲單向websocket。只有服務器能夠將消息發送到訂閱的客戶端。在許多Web應用程序中,Web套接字可能會過大。
  例如,商品的價格不須要雙向通訊。服務器僅須要單向通訊來更新其全部客戶端的價格。
  可是在客戶端與服務端須要強交互的場景下,Web Socket還是最佳選擇

SSE vs Long-Polling

長輪詢是一種通訊方法,客戶端按期訪問服務器獲取新數據。
  適用於須要通過必定時間的計算或者人工干預的響應
  SSE一般用於快速生成事件的應用程序中,即時更新。
  長輪訓雖然能夠避免短輪訓形成的服務端過載,但在服務端返回數據後仍須要客戶端主動發起下一個長輪訓請求,等待服務端響應

特性&限制

  • 1.SSE是單向的git

    消息數據是從服務器到客戶端,單向傳遞
  • 2.若是不使用HTTP/2會受到最大打開鏈接數的限制web

    瀏覽器對每一個域名限制的http鏈接數爲6,這是跨標籤的。HTTP/2默認值是100

客戶端接受消息

瀏覽器EventSource實例將建立一個持久的HTTP鏈接,直到經過調用關閉eventSource.close()。
const es = new EventSource('/v1/index/es')
  es.onopen = () => {
    console.log('es open')
  }
  es.onerror = (err) => {
    console.log('err', err)
  }
  es.addEventListener('test', (res) => {
    const { data } = res
    console.log('來自服端消息:', data)
  })

服務端發送消息

發送事件須要使用text/event-stream類型。每一個消息均以文本塊形式發送,並以一對換行符結尾。
  • 1.格式 每條收到的消息都有如下字段的組合瀏覽器

    event 標識所描述事件類型的字符串
        若是指定了 在瀏覽器上將觸發指定的偵聽器
        addEventListener()用於偵聽命名事件。
        onmessage則處理未指定事件名稱的消息。
    
      data 消息的數據字段
      id 事件ID
      retry 嘗試發送事件時要使用的從新鏈接時間 必須是整數,以毫秒爲單位
    1. 代碼
    const { Readable } = require('stream')
      // 寫入數據
      const send = (stream, event, data) => {
        return stream.push(`event:${event}\ndata: ${JSON.stringify(data)}\n\n`)
      }
      router.all('/es', async (ctx) => {
        // 建立流
        const reader = new Readable()
        reader._read = function (data) {
          console.log('>')
        }
    
        ctx.set({
          'Content-Type': 'text/event-stream', // 響應格式
          'Cache-Control': 'no-cache',
          'Connection': 'keep-alive'
        })
    
        send(reader, 'test', { data: 111 })
    
        ctx.body = reader
        let count = 1
        // 模擬消息發送
        const timer = setInterval(() => {
          send(reader, 'test', { data: 111, count: count++ })
        }, 3000)
    
        // 處理鏈接斷開
        ctx.req.on('close', () => {
          console.log('close')
          clearInterval(timer)
          reader.destroy()
        })
      })

代碼倉庫

https://gitee.com/wjj0720/ser...
相關文章
相關標籤/搜索