编程 不止 WebSocket 可以实现长连接,它也可以:Server-Sent Events(SSE)

2024-11-19 02:59:49 +0800 CST views 999

不止 WebSocket 可以实现长连接,它也可以:Server-Sent Events(SSE)

在前端开发中,服务端消息推送通常会使用 WebSocket,特别是在聊天室应用场景中。虽然 WebSocket 提供了双向通信的能力,但并不是唯一的长连接解决方案。Server-Sent Events(SSE)也可以用于基于服务端的消息推送,但它是单向的,数据只能从服务端发送到客户端。

例如,像 ChatGPT 这样的应用场景下,文本输出就是基于服务器的消息推送来进行数据的实时输出。本文将介绍如何使用 EventSource 实例来实现与服务端的通信,并实现消息推送。

1. 什么是 EventSource

EventSource 是一个用于接收服务端推送消息的实例,它基于 HTTP 的长连接,能够始终保持开启状态,直到调用 close 方法关闭连接。需要注意的是,EventSource 不支持通过 axios 进行实现,因为 axios 使用的是 XMLHttpRequest,无法处理服务端推送消息。

后端服务示例

首先,我们需要实现一个简单的后端服务,使用 SSE 推送数据给前端。下面是一个基于 Node.js 的示例:

const article = `警告:当不使用 HTTP/2 时.....。`
app.get('/chat_typing', (req, res) => {
  // 开启 Server-sent events
  res.setHeader('Content-Type', 'text/event-stream')
  let index = 0
  let timerId = 0
  // 模拟每隔 0.1s 向前端推送一次
  timerId = setInterval(() => {
    // 获取文字
    const data = article[index]
    // 下标累加
    index++
    // 响应结果
    if (data) {
      // data:表示数据内容,\n\n 表示结尾。
      res.write(`data: ${data}\n\n`)
    } else {
      res.end()
      clearInterval(timerId)
    }
  }, 100)
})

在这个示例中,服务器每 100 毫秒向前端推送一个字符,Content-Type 设置为 text/event-stream,表示这是 SSE 消息推送。

前端接收消息

在前端,我们可以通过 EventSource 实例来建立长连接,并接收服务端的消息推送。以下是基于 Vue.js 的示例:

<script setup>
import { ref } from 'vue'

const article = ref('')
let source
const OpenSSE = () => {
  source = new EventSource('http://localhost:3000/chat_typing')
  // 接收信息
  source.addEventListener('message', (e) => {
    // 实时输出字符串
    article.value += e.data
  })
}
</script>

<template>
  <div>
    <button @click="OpenSSE">开启SSE</button>
    <div>{{ article }}</div>
  </div>
</template>

当点击按钮时,前端将会开启与服务器的连接,并通过 EventSource 实例监听服务器发送的消息。在接收到的消息中,每个字符会逐步显示在页面上。

关闭连接

如果我们需要关闭这个长连接,可以调用 EventSource 实例的 close 方法:

const CloseSSE = () => {
  source.close()
}

2. 使用 fetch 优化连接

虽然 EventSource 适用于简单的消息推送场景,但它只支持 GET 请求,并且参数只能通过 URL 拼接传递。如果需要传递更多上下文或使用 POST 请求,那么 fetch 可以更好地处理这种情况。

基于 fetch 的长连接

以下是使用 fetch 来代替 EventSource 实现连接和数据推送的代码示例:

const OpenSSE = async () => {
  const res = await fetch('http://localhost:3000/chat_typing')
  console.log(res)
}

为了终止请求,我们可以使用 AbortController 来控制请求的终止操作:

const abort = new AbortController()
const OpenSSE = async () => {
  const res = await fetch('http://localhost:3000/chat_typing', {
    signal: abort.signal,
  })
  console.log(res)
}
const CloseSSE = () => {
  abort.abort()
}

AbortController 可以用来终止未完成的异步操作,在长连接中非常有用。

解析返回的流

通过 fetch 获取服务器的流数据,接着我们可以使用 res.body.getReader() 读取数据流。getReader() 返回一个 Promise,我们可以逐块读取流数据。

const OpenSSE = async () => {
  const res = await fetch('http://localhost:3000/chat_typing', {
    signal: abort.signal,
  })
  const content = res.body.getReader()
  const decoder = new TextDecoder()
  while (content) {
    const { done, value } = await content.read()
    if (done) break
    console.log(decoder.decode(value))
  }
}

content.read() 是异步操作,返回的 valueUint8Array 格式的数据,需要通过 TextDecoder 转换为字符串。

支持 POST 请求的示例

在某些场景下,我们可能需要通过 POST 请求来传递更多的上下文信息。以下是修改为 POST 请求的示例:

后端:

app.post('/chat_typing', (req, res) => {
  // 处理 POST 请求
  res.write({ data: 'some data' })
})

前端:

const OpenSSE = async () => {
  const res = await fetch('http://localhost:3000/chat_typing', {
    method: 'POST',
    signal: abort.signal,
  })
  const content = res.body.getReader()
  const decoder = new TextDecoder()
  while (content) {
    const { done, value } = await content.read()
    if (done) break
    console.log(decoder.decode(value))
  }
}

3. 总结

本文展示了如何使用 EventSourcefetch 来实现服务器消息推送的长连接机制。

  • EventSource:适用于简单的消息推送场景,易于使用,但只支持 GET 请求,且参数只能通过 URL 传递。
  • fetch:提供了更多的灵活性,支持 POST 请求、传递参数,并可以处理数据流。

SSE 和 fetch 都可以用于实现长连接,常用于消息推送、提醒等功能。

复制全文 生成海报 前端开发 网络通信 实时数据推送

推荐文章

PHP 如何输出带微秒的时间
2024-11-18 01:58:41 +0800 CST
在 Vue 3 中如何创建和使用插件?
2024-11-18 13:42:12 +0800 CST
js迭代器
2024-11-19 07:49:47 +0800 CST
CSS Grid 和 Flexbox 的主要区别
2024-11-18 23:09:50 +0800 CST
四舍五入五成双
2024-11-17 05:01:29 +0800 CST
Hypothesis是一个强大的Python测试库
2024-11-19 04:31:30 +0800 CST
Vue3中如何处理异步操作?
2024-11-19 04:06:07 +0800 CST
vue打包后如何进行调试错误
2024-11-17 18:20:37 +0800 CST
基于Flask实现后台权限管理系统
2024-11-19 09:53:09 +0800 CST
企业官网案例-芊诺网络科技官网
2024-11-18 11:30:20 +0800 CST
html一个包含iPhoneX和MacBook模拟器
2024-11-19 08:03:47 +0800 CST
thinkphp swoole websocket 结合的demo
2024-11-18 10:18:17 +0800 CST
html折叠登陆表单
2024-11-18 19:51:14 +0800 CST
JavaScript设计模式:桥接模式
2024-11-18 19:03:40 +0800 CST
Git 常用命令详解
2024-11-18 16:57:24 +0800 CST
Vue3中如何实现状态管理?
2024-11-19 09:40:30 +0800 CST
程序员茄子在线接单