我们知道 ,ChatGPT API是一个OpenAI 的聊天机器人接口,它可以根据用户的输入生成智能的回复。为了提高聊天的流畅性和响应速度,ChatGPT API采用了SSE作为服务端推送技术。SSE是一种HTML5技术,它允许服务器向客户端发送事件,从而实现服务器端推送。相对于WebSockets或长轮询技术,SSE提供了更简单的方式来实现服务器端推送,并且支持更广泛的客户端和服务器端。
通过SSE技术,ChatGPT API可以实现流式响应,即服务器不需要等待客户端的请求,就可以主动发送数据给客户端。这样可以减少网络延迟和资源消耗,提高聊天的效率和质量。
在Web开发中,有时我们需要从服务器端实时地向浏览器端发送数据,以提高用户体验和交互效果。例如,聊天应用、股票行情、新闻更新等场景都需要服务器端主动地推送数据给浏览器端。那么,如何实现这样的功能呢?没错,依然是SSE。
HTML代码:
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>EventSource Example</title>
</head>
<body>
<div id="messages"></div>
<script>
var source = new EventSource('/message-stream');
source.onmessage = function(event) {
var message = JSON.parse(event.data);
var div = document.createElement('div');
div.innerHTML = message.user + ': ' + message.text;
document.getElementById('messages').appendChild(div);
};
</script>
</body>
</html>
Node.js服务器端代码:
var http = require('http');
http.createServer(function(request, response) {
response.writeHead(200, {
'Content-Type': 'text/event-stream',// 这个表示服务端流式响应
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
setInterval(function() {
var message = {
user: 'John',
text: 'Hello, world!'
};
response.write('data: ' + JSON.stringify(message) + '\n\n');
}, 1000);
}).listen(3000);
当然,SSE也有一些局限性,比如:
因此,在选择使用SSE技术之前,需要根据具体的应用场景和需求进行权衡。如果只需要从服务器向客户端发送更新频繁、低延迟的文本数据,并且不考虑IE和Edge浏览器的兼容性问题,那么SSE是一个很好的选择。
下面我们来具体介绍一下SSE的技术细节和实现方法。
要使用SSE技术,首先需要了解它的通信协议。SSE通信协议很简单,本质上就是一个客户端发起的HTTP GET请求,服务器在接收到该请求后,返回200 OK状态,并附带以下响应头:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
这些响应头的含义分别是:
在返回响应头之后,服务器端就可以开始向客户端发送数据了。SSE格式的数据是由一系列的事件组成的,每个事件都有以下几个部分:
SSE支持以下几种字段:
例如,一个简单的SSE事件可以写成这样:
data: Hello, world!
id: 1
event: message
或者这样:
data: Hello,
data: world!
id: 1
event: message
注意,每个事件必须以一个空行结束,否则客户端无法识别事件的边界。另外,如果一个字段没有值,那么只写字段名即可,例如:
event:
表示一个没有类型的事件。
服务器端可以根据需要发送任意数量和类型的事件,客户端会按照接收到的顺序处理这些事件。如果客户端在接收数据过程中发生了断线或错误,那么它会尝试重新连接服务器,并发送上次接收到的事件id作为Last-Event-ID请求头。服务器端在收到这个请求头后,可以根据id判断是否需要重发之前的事件。
要在浏览器端使用SSE技术,只需要使用原生的EventSource对象即可。EventSource对象是一个封装了SSE通信协议的对象,它提供了以下几个属性和方法:
除了这些属性和方法外,EventSource对象还支持addEventListener方法,可以用来监听自定义类型(有event字段)的事件。例如:
var source = new EventSource('http://example.com/sse');
source.onopen = function() {
console.log('SSE connection opened');
};
source.onmessage = function(e) {
console.log('Received default event:', e.data);
};
source.onerror = function(e) {
console.log('SSE error:', e);
};
source.addEventListener('message', function(e) {
console.log('Received message event:', e.data);
});
source.addEventListener('update', function(e) {
console.log('Received update event:', e.data);
});
使用EventSource对象非常简单,只需要创建一个实例,并传入SSE服务端的URL地址即可。然后就可以通过onopen、onmessage、onerror等属性或addEventListener方法来监听和处理服务器发送的事件了。
WebSockets是一种双向通信协议,它允许客户端和服务器之间建立一个全双工的TCP/IP连接,并在连接上交换二进制或文本数据。WebSockets相比于SSE有以下优缺点:
优点:
缺点:
服务端推送技术涉及到客户端和服务器之间的数据传输,因此需要考虑安全性问题。不同的服务端推送技术有不同的安全性特点:
综上所述,服务端推送技术在ChatGPT API中有着重要的应用,它可以提高聊天机器人的响应速度和用户体验。不同的服务端推送技术有各自的优缺点和安全性特点,需要根据具体的场景和需求来选择合适的技术。
/*
* 使用 koa 实现一个 post 的 sse 请求
请求方式 post
请求 path /api
参数straem 控制是否流式响应,stream=true 表示流式响应,否则普通响应
*/
const Koa = require("koa");
const Router = require("koa-router");
const bodyParser = require("koa-bodyparser");
const app = new Koa();
const router = new Router();
// Use bodyParser middleware to parse request body
app.use(bodyParser());
router.post("/api", async (ctx) => {
const { stream } = ctx.request.body;
if (stream == true) {
// Set response headers for SSE
ctx.response.set({
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
});
// Send SSE header
ctx.res.statusCode = 200;
ctx.res.write(":ok\n\n");
let count = 0;
// Set up SSE interval for streaming response
// Generate SSE data
while (count < 5) {
const data = {
message: "Hello, world!",
timestamp: Date.now(),
};
count++;
await new Promise((resolve) => setTimeout(resolve, 1000));
// Send SSE event
ctx.res.write(`data: ${JSON.stringify(data)}\n\n`);
}
ctx.res.write(":done\n\n");
// Handle closing of SSE connection
ctx.req.on("close", () => {
ctx.response.end();
});
} else {
// Send non-streaming response
ctx.body = { message: "Hello, world!" };
}
});
app.use(router.routes());
app.listen(3000);
使用postman来发起post请求,就可以看到
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。