SSE(server-sent events)是什么 MDN上有关于SSE的介绍,可以把SSE理解为单向的WebSocket。普通请求 + WebSocket + SSE联手一起完善了浏览器网络请求体系。它们的区别如下: 普通请求(GET,POST,PUT等等):浏览器--->服务器,单向非持续数据流。 WebSocket:浏览器<--->服务器,双向持续数据流。 SSE:浏览器<---服务器,单向持续数据流。 SSE的表现形式上和WebSocket差不多,依旧由浏览器主动发起请求,但是服务端不会立即返回,而是保持长连接,伺机返回数据,相应的,浏览器端则需要监听事件。 场景解析 知道了SSE能实现什么功能,你可能已经跃跃欲试了,但是SSE的使用场景是什么呢?为什么不直接使用WebSocket呢? 一个经典的使用场景就是AI聊天。在用户输入提问后,AI会流式地返回消息,所以浏览器发送提问后,就只需要持续接受消息,不需要再发送消息了。 以下内容以AI聊天为切入点,详解Nuxt3中如何实现这类需求。 需求 假设我们有一个api_key,用这个key可以和ChatGPT聊天,需求是:开发一个web应用,让所有访问者都可以和ChatGPT聊天,而用户不需要知道key是什么。简单来说,就是实现一个ChatGPT套壳。(假设ChatGPT的接口地址为https://chatgpt.com/chat是基于SSE的) 相关工具 在网上搜索后,我找到了以下信息/文档: Nuxt3目前已经原生支持SSE,提供createEventStream()函数,详见官方样例 一个很有价值的gist参考,用hookable实现NuxtServer的api间通信:gist 一个npm包,可以在nodejs里方便地创建SSE客户端:@fortaine/fetch-event-source 流程解析 流程图如下(第一次用obsidian的excalidraw做这么复杂的图,做得有点差,见谅): 流程详解: 浏览器生成一个随机uid,用来区分其他聊天。uid是必须的,否则无法区分聊天。 浏览器请求/api/start-sse接口,携带uid和prompt。 NuxtServer收到请求,开启一个fetch()请求ChatGPT的服务器,携带api_key和prompt(Nuxt作为sse的client)。随即返回{ success: true }。 浏览器开启一个EventSource(),接口地址是/api/sse,同时也携带uid。 NuxtServer收到请求,创建一个eventStream并返回(Nuxt作为sse的server),浏览器收到响应,触发onopen事件。 在第3步中,NuxtServer开启了一个fetch(),其响应是流式的,每次收到响应都会调用callHook(),触发/api/sse中的hook(),最终push()推送消息到了浏览器。 样例代码 我写了一个简单的示例项目,开源在Github,项目里不会真的调用ChatGPT,而是用Nuxt另外起了一个SSE接口,每隔一秒返回当前时间:
Nuxt3创建SSE server以及client的简明教程
SSE(server-sent events)是什么
MDN上有关于SSE的介绍,可以把SSE理解为单向的WebSocket。普通请求 + WebSocket + SSE联手一起完善了浏览器网络请求体系。它们的区别如下:
SSE的表现形式上和WebSocket差不多,依旧由浏览器主动发起请求,但是服务端不会立即返回,而是保持长连接,伺机返回数据,相应的,浏览器端则需要监听事件。
场景解析
知道了SSE能实现什么功能,你可能已经跃跃欲试了,但是SSE的使用场景是什么呢?为什么不直接使用WebSocket呢? 一个经典的使用场景就是AI聊天。在用户输入提问后,AI会流式地返回消息,所以浏览器发送提问后,就只需要持续接受消息,不需要再发送消息了。 以下内容以AI聊天为切入点,详解Nuxt3中如何实现这类需求。
需求
假设我们有一个api_key,用这个key可以和ChatGPT聊天,需求是:开发一个web应用,让所有访问者都可以和ChatGPT聊天,而用户不需要知道key是什么。简单来说,就是实现一个ChatGPT套壳。(假设ChatGPT的接口地址为
https://chatgpt.com/chat
是基于SSE的)相关工具
在网上搜索后,我找到了以下信息/文档:
createEventStream()
函数,详见官方样例流程解析
流程图如下(第一次用obsidian的excalidraw做这么复杂的图,做得有点差,见谅):
流程详解:
/api/start-sse
接口,携带uid和prompt。fetch()
请求ChatGPT的服务器,携带api_key和prompt(Nuxt作为sse的client)。随即返回{ success: true }
。EventSource()
,接口地址是/api/sse
,同时也携带uid。onopen
事件。fetch()
,其响应是流式的,每次收到响应都会调用callHook()
,触发/api/sse
中的hook()
,最终push()
推送消息到了浏览器。样例代码
我写了一个简单的示例项目,开源在Github,项目里不会真的调用ChatGPT,而是用Nuxt另外起了一个SSE接口,每隔一秒返回当前时间: