长连接:ChatGPT流式响应背后的逻辑 | 京东物流技术团队
一、前言:
提起长连接,我们并不陌生,最常见的长连接非websocket莫属了。即使没有在项目中实际用过,至少也应该有所接触。长连接指在一次网络通信中,客户端与服务器之间建立一条持久的连接,可以在多次请求和响应中重复使用该连接。这种方式的优点是减少了连接建立和关闭的开销,提高了通信效率,但需要注意控制连接的数量,避免资源浪费。短连接则是每次请求和响应都建立一个新的连接,完成后立即关闭,需要频繁进行连接建立和关闭,效率相对较低。但是这种方式更加灵活,适用于请求量较小、请求频率不高的场景。
二、背景:
最近项目在引用chatgpt智能小助手,最开始采用的是当chatgpt回答完成后一次性返回答案。但这种方式受限于网络及服务较慢的原因导致用户需要等待较长时间,极大的降低了用户的使用体验。经过项目组成员商议决定采取答案逐字返回的形式,以便于用户能更快的得到反馈。
关于长连接技术,主要考虑两种方案websocket和sse
三、原理:
1.websocket概念:WebSocket是HTML5定义的新协议,实现了服务器与客户端之间的全双工通信。WebSocket连接一旦建立,客户端和服务器端处于平等地位,可以相互发送数据,不存在请求和响应的区别。
2、websocket优劣势:优势在于实现了双向通信,劣势在于服务器端的逻辑非常复杂。现在针对不同的后台语言有不同的插件可以使用。
3、sse概念:SSE(Server-Sent Events)是HTML5新增的功能,允许服务器将数据推送到客户端。与长轮询和短轮询不同,SSE不需要客户端先发送请求,而是在服务器端数据有更新时立即发送到客户端
4、sse优劣势:优势在于节约资源,提升应用性能。SSE可以实现只要服务器端数据有更新,就可以马上发送到客户端,不需要建立或保持大量的客户端发往服务器端的请求。另外,SSE的实现非常简单,并且不需要依赖其他插件。劣势在于不是双向通信,只能后台向前台推送。
5、相同点:都是基于tcp,都是可靠的传输协议
6、不同点:
- WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息
- HTTP是单向的
- WebSocket是需要浏览器和服务器握手进行建立连接的
- 而http是浏览器发起向服务器的连接,服务器预先并不知道这个连接
四、应用:
1、sse在chatgpt中的应用
前端代码
import { fetchEventSource } from '@microsoft/fetch-event-source'
let answerContent = ''
fetchEventSource('/chatgptApi/chatgpt_qa_stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ messages }),
async onopen(response) {
if (response.ok && response.status === 200) {
console.log('连接成功')
} else {
console.log('连接异常')
}
},
async onmessage(event) {
// 表示整体结束
if (event.data === '[DONE]') {
console.log('结束')
return
}
if (event.data) {
const data = JSON.parse(event.data)
answerContent += data.content
}
},
async onerror(error) {
console.error('Error:', error)
},
async onclose() {
console.log('关闭连接')
}
})
后端代码
const http = require('http');
const yun = express();
const eventServer = http.createServer((req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': "*",
'Access-Control-Allow-Headers': 'Content-Type,Content-Length,Authorization,Accept,X-Requested-With',
'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS'
});
setInterval(() => {
// 事件要用两个\n结束
res.write('data: The server time is: ' + new Date() + '\n\n');
}, 1000);
req.connection.addListener('close', () => {
console.log('SSE connection closed!');
}, false);
}).listen(4001);
2、websockt在即时聊天中的应用
前端代码
// 创建WebSocket对象
let ws = new WebSocket('ws://localhost:8888')
// 连接成功后的回调函数
ws.onopen = function (params) {
console.log('客户端连接成功')
// 向服务器发送消息
ws.send('hello')
};
// 从服务器接受到信息时的回调函数
ws.onmessage = function (e) {
console.log('收到服务器响应', e.data)
};
// 连接关闭后的回调函数
ws.onclose = function(evt) {
console.log("关闭客户端连接");
};
// 连接失败后的回调函数
ws.onerror = function (evt) {
console.log("连接失败了");
};
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,这样服务端会抛异常。
window.onbeforeunload = function() {
ws.close();
}
后端代码
/ 引入插件
const ws = require('nodejs-websocket')
// 只要有用户链接,函数就会执行,会给当前链接的用户创建一个connect对象
const server = ws.createServer((connect)=>{
console.log('连接成功')
// console.log(connect)
// 注册text事件 ,接收用户传递过来的数据
connect.on('text',data=>{
console.log('接收客户端数据---->', data)
// 给所有用户发送消息
broadcast(server,data+"--返回数据")
})
// 连接断开,触发事件close
connect.on('close',()=>{
console.log('用户链接断开--close')
})
// 用户链接断开
connect.on('error',err=>{
console.log('err', err)
})
}).listen(3001,()=>{
console.log('websocket服务启动成功了')
})
// 给所有人发消息
function broadcast(server,msg){
server.connections.forEach(element => {
element.send(msg)
});
}
五、效果:
sse在chatgpt案例中的应用
作者:京东物流 田雷雷
来源:京东云开发者社区 自猿其说Tech

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
初探webAssembly | 京东物流技术团队
1 WebAssembly是什么? 一种运行在现代网络浏览器中的新型代码,并且提供新的性能特性和效果 W3C WebAssembly Community Group开发的一项网络标准,对于浏览器而言,WebAssembly 提供了一条途径,让各种语言编写的代码以接近原生的速度在 Web 中运行。在这种情况下,以前无法以此方式运行的客户端软件等都将可以运行在 Web 中。 WebAssembly 设计之初就决定和 JavaScript 一起协同运行——通过JavaScript 中的 WebAssembly API,可以把 WebAssembly 模块加载到一个 JavaScript 应用中并且在两者之间互相调用。这样可以在同一个应用中使用 WebAssembly 的高性能及 JavaScript 的高灵活性。 2 为什么需要WebAssembly? 众所周知JavaScript是解释型语言,相比于编译型语言需要在运行时转换,所以解释型语言的执行速度要慢于编译型语言。 编译型语言和解释型语言代码执行的具体流程如下: 因为解释型语言每次执行都需要把源码转换一次才能执行,而转换过程非常耗费时间...
-
下一篇
用Rust生成Ant-Design Table Columns | 京东云技术团队
经常开发表格,是不是已经被手写Ant-Design Table的Columns整烦了? 尤其是ToB项目,表格经常动不动就几十列。每次照着后端给的接口文档一个个配置,太头疼了,主要是有时还会粘错就尴尬了。 那有没有办法能自动生成columns配置呢? 当然可以。 目前后端的接口文档一般是使用Swagger来生成的,Swagger是基于OpenAPI规范的一种实现。(OpenAPI规范是一种描述RESTful API的语言无关的格式,它允许开发者定义API的操作、输入和输出参数、错误响应等信息,并提供了一种规范的方式来描述和交互API。) 那么我们只需要解析Swagger的配置就可以反向生成前端代码。 接下来我们就写个CLI工具来生成Table Columns。 平常我们实现一个CLI工具一般都是用Node,今天我们搞点不一样的,用Rust。 开始咯 swagger.json 打开后端用swagger生成的接口文档中的一个接口,一般是下面这样的,可以看到其json配置文件,如下图: swagger: 2.0表明了这个文档使用的swagger版本,不同版本json配置结构会不同。 path...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Red5直播服务器,属于Java语言的直播服务器
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8编译安装MySQL8.0.19
- MySQL数据库在高并发下的优化方案
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池