前端基于SSE实现类似GPT打字机效果
WHAT
Server-Sent Events(以下简称SSE)是一种用于实现服务器向客户端实时推送数据的Web技术。与传统的轮询和长轮询相比,SSE提供了更高效和实时的数据推送机制。
SSE基于HTTP协议,允许服务器将数据以事件流(Event Stream)的形式发送给客户端。客户端通过建立持久的HTTP连接,并监听事件流,可以实时接收服务器推送的数据。
SSE的主要特点
- 简单易用:SSE使用基于文本的数据格式,如纯文本、JSON等,使得数据的发送和解析都相对简单。
- 单向通信:SSE支持服务器向客户端的单向通信,服务器可以主动推送数据给客户端,而客户端只能接收数据。
- 实时性:SSE建立长时间的连接,使得服务器可以实时地将数据推送给客户端,而无需客户端频繁地发起请求。
SSE与WebSocket的比较
WebSocket是另一种用于实现实时双向通信的Web技术,它与SSE在某些方面有所不同。下面是SSE和WebSocket之间的比较:
- 数据推送方向:SSE是服务器向客户端的单向通信,服务器可以主动推送数据给客户端。而WebSocket是双向通信,允许服务器和客户端之间进行实时的双向数据交换。
- 连接建立:SSE使用基于HTTP的长连接,通过普通的HTTP请求和响应来建立连接,从而实现数据的实时推送。WebSocket使用自定义的协议,通过建立WebSocket连接来实现双向通信。
- 兼容性:由于SSE基于HTTP协议,它可以在大多数现代浏览器中使用,并且不需要额外的协议升级。WebSocket在绝大多数现代浏览器中也得到了支持,但在某些特殊的网络环境下可能会遇到问题。
- 适用场景:SSE适用于服务器向客户端实时推送数据的场景,如股票价格更新、新闻实时推送等。WebSocket适用于需要实时双向通信的场景,如聊天应用、多人协同编辑等。
前端基于SSE实现类似GPT打字机效果
安装
npm install @microsoft/fetch-event-source --save
使用
<script>
import { fetchEventSource } from '@microsoft/fetch-event-source'
export default {
data() {
return {
controller: null
};
},
methods: {
onSend() {
// 业务逻辑
this.sendSSEMessage(param, '内容')
},
sendSSEMessage(param, userQuery) {
let message = ''
let getFirst = false // 是否为收到的第一条消息
let hasDone = false // 消息结束
if (!this.controller) {
//信号对象,可以用来取消与Fetch API相关的操作
this.controller = new AbortController()
const signal = this.controller.signal
fetchEventSource('流式接口路径', {
method: 'POST',
signal: signal,
headers: {
"Content-Type": 'application/json'
},
body: JSON.stringify(param),
// openWhenHidden: 监听visibilitychange,当页面不可见时关闭连接,当页面重新可见时重新打开连接
openWhenHidden: true,
onmessage: (event) => {
let data = null
try {
data = JSON.parse(event.data);
} catch (error) {
console.log('parse error')
}
if(data){
if (data.code == '-1') {// 根据实际返回的数据判断
console.log('请求失败')
this.closeCtrl()
} else if (hasDone) {
// 结束
this.closeCtrl()
} else {
if (!getFirst) {
getFirst = true
message += data.content // 拼接字符串
// 这边可以修改展示内容
}
}
}
if (event.data == '[DONE]') {
hasDone = true
}
},
onerror: (err) => {
console.log('SSE抛出异常')
this.closeCtrl()
throw err;
},
onclose: () => {
this.closeCtrl()
}
})
}
},
closeCtrl() {
/**
* 取消fetch请求,一般在以下场景应当关闭
* 1、接收到与后端约定的含有错误标识的消息
* 2、结束会话
* 3、在页面离开时,丢弃未完成的请求
* 4、连接出现异常回调
*
* 注意:abort方法可以被多次调用,但第二次及以后的调用不会有任何效果。一旦请求被取消,它将保持取消状态。
*/
if (this.controller) {
this.controller.abort()
this.controller = null
}
},
},
beforeDestroy() {
this.closeCtrl()
},
};
</script>