最近在玩chatGPT的时候发现网页版上它是逐字输出的,有时候还会卡顿一下再接着输出,我就好奇它是使用什么方式进行数据传输的,通过浏览器开发者工具发现,它使用的是EventStream方式持续输出数据到前端的,了解之后发现这种方式在某些特定的场景下非常有用。
EventStream是什么
EventStream
是HTML5的新内容,特点就是返回的Content-Type
为text/event-stream
,其采用的是http协议,这种方式的请求浏览器不会关闭这个http连接,而是一直等待服务器的持续返回,达到一种长连接的效果,不过它是单向的,除了发送请求的时候可以传送一次数据到服务器,后面便只能等待服务器返回数据而不能发送数据,相当于是一个持续了很长时间的普通http请求,因此它需要浏览器的支持(微软的IE和Edge浏览器并未实现,可以采用第三方库实现)
优点
. 因为是http协议,所以无需其余实现即可使用
. 默认支持断线重连,不需要手动维护连接
. 支持自定义发送消息的类型
. 在单项传输的场景里面非常有用
缺点
. 只支持utf-8编码,不支持二进制数据
. 只支持单项传输,客户端不能主动发送数据给服务端
. 浏览器对最大打开连接数有限制
场景示例
异步任务的执行进度
比如某些政府系统会有大量导出报表的需求,这些报表数据量大,服务端采用异步处理的方式,前端通过接口去获取任务进度,这时候通过WebSocket
去实现就显得很麻烦,使用轮询处理不仅仅更新数据不及时,而且还需要不断重复建立http请求,这时候使用SSE的方式就显得极其简便和高效
具体实现
服务端代码
在spring boot中实现非常简单,接口内只要通过PrintWriter·flush()
即可不断将数据返回给客户端,这里采用PrintWriter.checkError()
是为了防止异常无法检测导致资源无法释放。
1 |
|
客户端代码
其实直接在浏览器访问上面接口就可以看到持续返回的内容:
不过在实际项目中肯定需要异步处理的方式,这里可以使用EventSource
对象,不过浏览器不支持的话就需要使用开头说的第三方库
1 | var source = new EventSource('http://localhost:8080/sse') |
运行结果:
是不是发现有点不一样,相比于用浏览器直接访问,这种方式少了前面的data:
,这是因为EventSource
语法约定的,如果服务端没有返回data:
格式,那么上面EventSource
的onmessage
监听函数里就不会有内容返回,而且必须以\n\n
表示一句话的结束,否则一直接不到内容,具体的语法使用规则这里不做赘述,可以直接看EventSource文档