Server-sent events

服务端进行数据推送除了WebSocket之外,还能够应用Server-Send-Event计划。

WebSocket不同的是,服务器发送事件是单向的。数据音讯只能从服务端到发送到客户端(如用户的浏览器)。这使其成为不须要从客户端往服务器发送音讯的状况下的最佳抉择。

Server-Sent-EventsSSE)是一种HTML5 API,用于在服务器和客户端之间实时推送数据流。 SSE能够用于实现实时告诉、实时聊天、实时数据更新和实时监控等性能。

服务器发送事件API蕴含在EventSource接口中

EventSource

EventSource 接口是 web 内容与服务器发送事件通信的接口。

一个 EventSource 实例会对HTTP服务器开启一个长久化的连贯,以 text/event-stream 格局发送事件,此连贯会始终放弃开启直到通过调用EventSource.close()敞开。

创立一个EventSource实例

创立一个EventSource对象,开启与服务器的连贯并接管事件

const evtSource = new EventSource("ssedemourl")

如果生成事件的代码不同源,须要创立一个新的蕴含url和options参数的EventSource对象

const evtSource = new EventSource("//api.example.com/ssedemourl", {  withCredentials: true,})

事件流格局

事件流是一个简略的文本数据流,文本应该应用 UTF-8格局的编码。事件流中的音讯由一对换行符离开。以冒号结尾的行为正文行,会被疏忽。

每个字段由字段名示意,前面是冒号,而后是该字段值的文本数据。

字段有以下几个

  • event

    用于标识事件类型的字符串。如果指定了这个字符串,浏览器会将具备指定事件名称的事件分派给相应的监听器;客户端应该应用 addEventListener() 来监听指定的事件。如果一个音讯没有指定事件名称,那么能够调用onmessage 处理程序。

  • data

    音讯的数据字段。当 EventSource 接管到多个以 data: 结尾的间断行时,会将它们连接起来,在它们之间插入一个换行符。开端的换行符会被删除。

  • id

    事件 ID,会成为以后 EventSource 对象的外部属性“最初一个事件 ID”的属性值。

  • retry

    从新连贯的工夫。如果与服务器的连贯失落,浏览器将期待指定的工夫,而后尝试从新连贯。这必须是一个整数,以毫秒为单位指定从新连贯的工夫。如果指定了一个非整数值,该字段将被疏忽。

所有其余的字段名都会被疏忽。

示例:

纯数据messagee

data: some text

命名事件

event:usermessagedata: {"username": "bobby", "age": "22"}

混合事件,在一个事件流中同时应用命名事件和未命名事件

data: some textevent:usermessagedata: {"username": "bobby", "age": "22"}

监听open事件

EventSource接口的onopen属性是一个事件处理器,它在收到 open 事件时被调用,在那时,连贯刚被关上。

evtSource.onopen = function () {  console.log("Connection to server opened.");}

监听message事件

如果服务器发送的音讯中没有定义event字段,这些音讯则都为message事件,要接管从服务端发送过去的message事件,须要为message事件增加事件处理程序

前端局部代码:

evtSource.onmessage = (event) => {    console.log(event.data)}// onmessage的等价写法evtSource.addEventListener('message', (event) => {    console.log(event.data)});

服务端局部示例代码:

stream.write(`data: ${song[index]}\n\n`)

监听event字段中的自定义事件

如果服务器发送的音讯中定义了event字段,以event中给定的名称来接管事件

前端局部代码:

evtSource.addEventListener('custom', (e) => {    console.log(.data)})

服务端局部示例代码:

stream.write(`event: custom\ndata: ${song[index]}\n\n`) // 此处定义了event字段,名称为custom

处理错误事件

当发送网络超时或其余问题时,会生成一个谬误事件。在事件源连贯未能关上时触发

evtSource.onerror = (err) => {  console.error("EventSource failed:", err);}

敞开EventSource事件

默认状况下,如果客户端和服务器之间的连贯敞开,则SSE连贯会重新启动,能够在前端的事件上调用close()办法终止连贯。

evtSource.close()

从服务端发送事件示例

发送事件的服务端脚本须要应用text/event-streamMIME类型响应类型。每个告诉以文本块模式发送,并以一对换行符结尾。

Node.js中应用koa2演示SSE连贯,服务端示例代码

const router = require('koa-router')()const { PassThrough } = require('stream') // 测试EventSourcerouter.get('/eventSource', async (ctx, next) => {  try {    const stream = new PassThrough()    ctx.set({ 'Content-Type':'text/event-stream' })    // 将歌词变成一个数组    let song = [      '我', '懒', '得', '写', '你', '谷', '搜', '到', '处', '皆', '只', '因', '你',       '太', '美', '浅', '唱', '动', '人', '说', '不', '出', '我', '试', '着', 'end',     ]    let index = 0;    setInterval(() => {      const str = song[index];      if (str) {        // 形式1:格局是 data: xxx\n\n,事件要一对\n完结        // stream.write(`data: ${song[index]}\n\n`)        // 形式2,定义了event字段,自定义事件        stream.write(`event: custom\ndata: ${song[index]}\n\n`)        // 发送的数据为json字符串        // stream.write(`event: custom\ndata: {"name": "${song[index]}"}\n\n`)      } else {        stream.write('0')      }      index++    }, 500)    ctx.body = stream  } catch (error) {    error.status = error.status ? error.status : 500    ctx.throw(error.status, error)  }})

客户端接管示例

前端应用的vue3

const getSSE = () => {  const source = new EventSource(`http://localhost:8081/api/eventSource`);  let str = ''    source.onopen = () => console.log("Connected");  source.onerror = console.error;  // 形式1:监听message事件  // source.onmessage = (e) => {  //   if (e.data === 'end') {  //     // 断定end,敞开连贯  //     source.close()  //   }  //   str += e.data  //   console.log(str)  // }  // 形式2,监听自定义custom事件  source.addEventListener('custom', (e) => {    str += e.data    // str += JSON.parse(e.data).name // 接管json字符串    console.log(str)  })}getSSE()

成果演示

当初很火的ChatGPT在答复中的打字成果就是应用了SSE的形式。

结语

❤️ 大家喜爱我写的文章的话,欢送大家点点关注、点赞、珍藏和转载!!

欢送关注公众号前端开心果 我会继续更新前端相干的内容文章哦。