面试官:看你简历写着精通ChatGPT
实现敏捷、高质量开发?那你知道它是如何做到实时对话的么?
我:web-socket?
面试官:回去等通知吧~
之后翻阅才知道ChatGPT
用的是EventSource
,相比其他的通信如Web-socket
而言它更轻量级和简单 ,且对资源消耗 更少,最重要一个原因是GPT
主要关注从服务器向客户端推送消息的场景,而不需要客户端主动向服务器发送消息。EventSource
正是为此类单向通信 设计的,它允许服务器发送事件到客户端,而客户端只能接收事件,不能发送。对于ChatGPT
这样的应用来说,这种单向通信模式可能就足够了。
废话不多说,我们来看看EventSource
的基本用法
基本用法
EventSource
是HTML5中新增的一个API,它允许服务器通过HTTP连接向客户端推送消息。与传统的HTTP请求-响应模式不同,EventSource
使用了一个持久的连接,使得服务器可以在任何时候向客户端发送数据。这种单向通信模式非常适合用于实时更新、实时通知等场景。
- 关键特性
- 服务器向客户端单向推送数据。
- 基于HTTP长连接,连接一旦建立,服务器可以持续发送数据直到连接关闭。
- 客户端通过监听特定事件(如
message
)来接收服务器发送的数据。
- 常用方法
new EventSource(url)
: 创建一个新的EventSource对象,并连接到指定的URL。EventSource.onmessage
: 当服务器发送数据时触发的事件处理函数。EventSource.onerror
: 当连接发生错误时触发的事件处理函数。EventSource.onopen
: 当连接建立时触发的事件处理函数(注意:并非所有浏览器都支持此事件)。EventSource.close()
: 关闭连接。
实际应用场景
假设我们正在开发一个实时股票行情应用,需要实时显示股票价格的变动。使用EventSource
,我们可以轻松地实现这一功能。
服务器端可以设置为定期从股票数据API获取最新价格,并通过EventSource
发送给客户端。客户端则监听message
事件,一旦接收到新数据,就更新页面上的股票价格。
这种方式下,客户端无需不断轮询服务器以获取最新数据,从而减少了不必要的网络请求和服务器负载。同时,由于EventSource
是基于HTTP的,因此它可以轻松地穿透防火墙和代理服务器,提高了应用的可用性和稳定性。
接下来我们实战看看
实战例子
拿Vue为例子
xml
<template>
<div v-html="html">
</div>
</template>
<script>
export default {
data() {
return {
html: ''
}
},
mounted() {
this.handleEventSoure()
},
methods: {
handleEventSoure() {
const eventSource = new EventSource('/api/messages') // 连接地址
eventSource.onopen = () => { // 开始连接
}
eventSource.onmessage = (event) => { // 接收消息
this.html += `${event.data} </br>`
}
eventSource.onerror = () => { // 连接失败
}
}
}
}
</script>
通过new EventSource
进行对服务器的连接,并且配置相关连接处理函数。
后端则用node+express为例子
javascript
app.get('/messages', (req, res) => {
// 设置响应头,指明这是一个EventSource响应
res.setHeader('Content-Type', 'text/event-stream')
// 禁用缓存
res.setHeader('Cache-Control', 'no-cache')
// 保持长连接
res.setHeader('Connection', 'keep-alive')
// 发送一个初始消息
res.write('data: 连接成功\n\n')
// 连接关闭
req.on('close', () => {})
// 创建一个定时器来定期发送事件
const interval = setInterval(() => {
if (res.writable) {
const message = `时间: ${new Date().toISOString()}`
res.write(`data: ${message}\n\n`)
} else {
// 如果连接不再可写(可能已经关闭),则清除定时器
clearInterval(interval)
}
}, 1000) // 每1秒发送一次事件
// 当请求结束时(例如,客户端关闭连接),清除定时器
req.on('end', () => {
clearInterval(interval)
})
})
接下来我们看看效果吧:
EventSource
是一种简单且有效的实时通信协议,它利用HTTP长连接实现了服务器向客户端的单向数据推送。通过合理使用EventSource
的API和方法,我们可以轻松地构建出实时更新、实时通知等功能的Web应用。在实际应用中,我们需要根据具体需求选择合适的通信协议和方式,以实现相关业务。