前言
AI 对话已成为前端应用的必备功能,如何优雅地处理实时对话数据成为一个关键问题。本文将从 SSE、WebSocket、轮询到小程序专属方案,详细对比四种实现方式的优劣,帮助你在不同场景下选择最适合的解决方案。
实现方案对比
方案 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
SSE | 实现简单,实时性好 | 只支持单向通信 | 标准 Web 环境 |
微信小程序 enableChunked | 小程序原生支持 | 仅限微信小程序 | 微信小程序环境 |
轮询 | 兼容性好,实现简单 | 服务器压力大,实时性差 | 受限环境(如企业微信) |
webSocket | 全双工通信,实时性好 | 实现复杂,需要维护连接 | 对实时性要求高的场景 |
Server-Sent Events (SSE)
SSE 是一种服务器推送技术,允许服务器向客户端推送数据。它基于 HTTP 协议,单向通信(服务器到客户端)
async function* streamEvents<R = any>(readableStream: ReadableStream<Uint8Array>) {
const reader = readableStream.getReader();
const decoder = new TextDecoder('utf-8');
let data = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
data += decoder.decode(value, { stream: true });
while (true) {
const newlineIndex = data.indexOf('\n');
if (newlineIndex === -1) break;
const line = data.slice(0, newlineIndex);
data = data.slice(newlineIndex + 1);
if (line.startsWith('data:')) {
const text = line.slice('data:'.length).trim();
try {
const parsed = JSON.parse(text) as R
yield parsed;
} catch {
console.warn('Invalid JSON:', text);
}
}
}
}
}
// 使用示例
const stream = await fetch('xxx',{body: JSON.stringify({stream: true})});
const events = streamEvents(stream.body);
for await (const event of events) {
console.log(event);
}
微信小程序 enableChunked
微信小程序不支持 sse,但它提供了 enableChunked 来支持流式数据接收
const requestTask = wx.request({
url: `xxx`,
method: 'POST',
responseType: 'arraybuffer',
enableChunked: true,
// ...
});
requestTask.onChunkReceived(({ data }) => {
const uint8Array = new Uint8Array(data);
let text = String.fromCharCode.apply(null, uint8Array);
text = decodeURIComponent(escape(text));
if (data.indexOf('\n') !== -1) {
cosnole.log(text);
} else {
// end
}
});
注意 sse 和 微信小程序 enableChunked 都需要特定 nginx 配置
proxy_set_header Transfer-Encoding "";
chunked_transfer_encoding on;
proxy_buffering off;
企业微信环境下的轮询方案
由于企业微信环境的限制(不支持 SSE 和 enableChunked),可以采用轮询方案 实现思路: 发送消息时,服务端返回一个id,客户端根据id定期发送请求,查询是否有新数据,服务端使用 Redis 等存储中间数据
websocket
webSocket 提供了全双工通信能力,是实现实时对话的理想选择,但需要考虑更多的实现细节
总结
选择合适的 AI 对话实现方案需要考虑以下因素:
- 运行环境的限制
- 实时性要求
- 开发维护成本
- 服务器负载
不同场景下的最佳实践:
- Web 环境:优先考虑 SSE
- 微信小程序:使用 enableChunked
- 受限环境:采用轮询方案
- 高实时性需求:考虑 webSocket