SSE(Server Sent Event)消息推送

SSE(Server Sent Event)消息推送

消息推送是指服务端项客户端主动推送消息。

SSE 的本质

严格地说,HTTP 协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息(streaming)。也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。本质上,这种通信就是以流信息的方式,完成一次用时很长的下载。SSE 就是利用这种机制,使用流信息向浏览器推送信息。SSE基于 HTTP 协议中的持久连接,具有由 W3C 标准化的网络协议和 EventSource 客户端接口,作为 HTML5 标准套件的一部分,目前除了 IE/Edge,其他浏览器都支持。

SSE 和 websocket的区别

  1. SSE是基于HTTP协议的,而websocket是基于websocket协议的。
  2. SSE相对于websocket更加轻量,而且使用比较简单。
  3. SSE默认支持断线重连,而websocket需要自己实现断线重连。
  4. SSE是以文本进行数据传输,而websocket是以二进制进行传输。
  5. SSE支持自定义发送的消息类型。
  6. SSE 是单向通道只能服务器向浏览器发送,而WebSocket是全双工通道,可以双向通信,所以更强大和灵活。

客户端API

  1. SSE 的客户端 API 部署在EventSource对象上。使用前先检测浏览器是否支持 SSE
if ('EventSource' in window) {
    
    }
  1. 浏览器生成一个EventSource实例,向服务器发起连接。url可以与当前网址同域,也可以跨域。跨域时,可以指定第二个参数,打开withCredentials属性,表示是否一起发送 Cookie。
var source = new EventSource(url,{
    
     withCredentials: true });
  1. EventSource实例的readyState属性,表明连接的当前状态。该属性只读,可以取以下值:

0:相当于常量EventSource.CONNECTING,表示连接还未建立,或者断线正在重连。
1:相当于常量EventSource.OPEN,表示连接已经建立,可以接受数据。
2:相当于常量EventSource.CLOSED,表示连接已断,且不会重连。

  1. 连接一旦建立,就会触发open事件,可以在onopen属性定义回调函数.
// 写法一
source.onopen = function (event) {
    
    
  
};
// 写法二
source.addEventListener('open', function (event) {
    
    

}, false);
  1. 客户端收到服务器发来的数据,就会触发message事件,可以在onmessage属性的回调函数。
// 写法一
source.onmessage = function (event) {
    
    
  var data = event.data;
  
};
// 写法二
source.addEventListener('message', function (event) {
    
    
  var data = event.data;
}, false);
  1. 如果发生通信错误(比如连接中断),就会触发error事件,可以在onerror属性定义回调函数。
// 写法一
source.onerror = function (event) {
    
    
  
};
// 写法二
source.addEventListener('error', function (event) {
    
    
 
}, false);
  1. close方法用于关闭 SSE 连接。
source.close();
  1. 默认情况下,服务器发来的数据,总是触发浏览器EventSource实例的message事件。开发者还可以自定义 SSE 事件,这种情况下,发送回来的数据不会触发message事件。
source.addEventListener('自定义 SSE 事件', function (event) {
    
    
  var data = event.data;
}, false);

客户端示例

sse封装

class SseClient {
    
    
  sseUrl = ''
  source = null;
  openCallback = null;
  errorCallback = null;
  messageCallback = null;
  constructor(sseUrl, openCallback, errorCallback, messageCallback) {
    
    
    this.sseUrl = sseUrl
    this.openCallback = openCallback
    this.errorCallback = errorCallback
    this.messageCallback = messageCallback
    this.connect()
  }
  connect() {
    
    
    if ('EventSource' in window) {
    
    
      // sseUrl可以与当前网址同域,也可以跨域。跨域时,可以指定第二个参数,打开withCredentials属性,表示是否一起发送 Cookie
      this.source = new EventSource(this.sseUrl)
      // 连接一旦建立,就会触发open事件,可以在onopen属性定义回调函数
      this.source.onopen = (event) => {
    
    
        this.open(event)
      }
      // 如果发生通信错误(比如连接中断),就会触发error事件,可以在onerror属性定义回调函数。
      this.source.onerror = (event) => {
    
    
        this.error(event)
      }
      // 客户端收到服务器发来的数据,就会触发message事件,可以在onmessage属性的回调函数
      this.source.onmessage = (event) => {
    
    
        this.message(event)
      }
    } else {
    
    
      alert('当前浏览器不支持SSE!')
    }
  }
  open(event) {
    
    
    this.openCallback && this.openCallback(event)
  }
  error(event) {
    
    
    this.errorCallback && this.errorCallback(event)
  }
  message(event) {
    
    
    this.messageCallback && this.messageCallback(event)
  }
}

/**
 * 监听SSE的通用方法
 * @param sseUrl:SSE的连接地址
 * @param openCallback:SSE连接成功建立时的回调函数
 * @param errorCallback:SSE发生通信错误时的回调函数
 * @param messageCallback:客户端收到服务器发来数据时的回调函数
 * @returns {SseClient}
 */
export default (sseUrl, openCallback, errorCallback, messageCallback) => {
    
    
  return new SseClient(sseUrl, openCallback, errorCallback, messageCallback)
}

调用

    connectSSE() {
      this.sse = SseClient('http://127.0.0.1:8844/stream', this.open, this.error, this.message)
    },
    open(event) {
      console.log('open', event)
    },
    error(event) {
      console.log('error', event)
    },
    message({ data }) {
      console.log(data)
    },

Node服务端示例

var http = require("http");
http.createServer(function (req, res) {
    
    
  var fileName = "." + req.url;

  if (fileName === "./stream") {
    
    
    res.writeHead(200, {
    
    
      "Content-Type":"text/event-stream",
      "Cache-Control":"no-cache",
      "Connection":"keep-alive",
      "Access-Control-Allow-Origin": '*',
    });
    // 服务器可以用retry字段,指定浏览器重新发起连接的时间间隔
    res.write("retry: 10000\n"); 
    // event字段表示自定义的事件类型,默认是message事件。浏览器可以用addEventListener()监听该事件。
    // 自定义connecttime事件
    res.write("event: connecttime\n");
    // 数据内容用data字段表示。
    res.write("data: " + (new Date()) + "\n\n");
    res.write("data: " + (new Date()) + "\n\n");

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

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

前端相关依赖包

vue-sse

参考链接

  1. SSE
  2. SSE

猜你喜欢

转载自blog.csdn.net/weixin_39893889/article/details/130290442