在nextjs中使用SSE

1,325 阅读2分钟

什么是SSE?

SSE全称为Server Send Event,顾名思义服务器发送事件。严格地说,HTTP 协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息(streaming)。

也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。本质上,这种通信就是以流信息的方式,完成一次用时很长的下载。

SSE 就是利用这种机制,使用流信息向浏览器推送信息。它基于 HTTP 协议,目前除了 IE/Edge,其他浏览器都支持。

SSE的用法

1. 客户端

使用SSE时,首先在客户端生成一个EventSource对象,向服务器发起连接

var source = new EventSource(url)

连接建立之后,就会调用下面的方法

source.onopen=function(event){
    //...
}
//另一种写法
source.addListener('open',functin(event){
    //...
}

客户端收到服务器消息就会触发message事件

source.onmessage=function(event){
    console.log(event.data)
}

出现通信错误就会触发error事件

source.onerror=funtion(event){
    console.log(event)
}

自定义事件

source.addListener('foo',function(event){
    //...
}

上面代码中,浏览器对 SSE 的foo事件进行监听。

2. 服务器

服务器向浏览器发送的 SSE 数据,必须是 UTF-8 编码的文本,具有如下的 HTTP 头信息。

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

每一次发送的信息,由若干个message组成,每个message之间用\n\n分隔。每个message内部由若干行组成,每一行都是如下格式。

[field]: value\n

上面的field可以取四个值。

data//表示数据内容
event//表示事件
id//代表数据标识
retry//表示重连时间

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": '*',
    });
    res.write("retry: 10000\n");
    res.write("event: connecttime\n");
    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");

在nextjs中使用需要注意

  1. 客户端无法接收到数据,需要如下设置
async function handler(req: NextApiRequest, res: NextApiResponse){
    res.setHeader('Content-Type', 'text/event-stream;charset-utf-8');
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('X-Accel-Buffering', 'no');
    res.setHeader('Cache-Control', 'no-cache, no-transform');
}

主要是设置'no-cache, no-transform',因为nextjs默认会压缩内容。

  1. 客户端无法收到data中的换行符,解决办法是对于有空格符的消息添加自定义事件,客户端监听进行空格符的添加