部门项目集成了文心一言
和ChatGPT4.0
等大模型,之前的数据返回方式采用了轮询的方法,现在要替换成 Server-Sent Events
协议。
前提:项目前端采用了 Umijs
后端采用了 Flask
首先开始了对 SSE 的学习,分别搭建了简单的 express
服务 和 使用 vite
的前端项目
服务端代码:
js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function (req, res, next) {
res.render('index', { title: 'Express' });
});
router.post('/stream', function (req, res, next) {
res.set({
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'no-cache',
Connection: 'keep-alive', // allowing TCP connection to remain open for multiple HTTP requests/responses
'Content-Type': 'text/event-stream', // media type for Server Sent Events (SSE)
});
res.flushHeaders();
const interval = setInterval(() => {
const stock1Rate = Math.floor(Math.random() * 100000);
const obj = {
content: stock1Rate,
contentType: 'text',
};
res.write("data: " + JSON.stringify(obj) + "\n\n");
}, 500);
setTimeout(() => {
clearInterval(interval);
res.end();
}, 3000);
});
module.exports = router;
前端代码:
js
const [data, setData] = useState('');
const str = useRef('');
useEffect(() => {
async function fetchData() {
const result = await fetch(`/stream`, { method: 'post' });
const reader = result.body?.getReader();
// Here we start prepping for the streaming response
const decoder = new TextDecoder();
const loopRunner = true;
while (loopRunner) {
// Here we start reading the stream, until its done.
const { value, done } = await reader!.read();
if (done) {
break;
}
const decodedChunk = decoder.decode(value, { stream: true });
console.log('decodedChunk', decodedChunk);
str.current+=decodedChunk
setData(str.current); // update state with new chunk
}
}
fetchData();
}, []);
运行结果:
项目中实践一下
将上述的前端代码拷贝到公司项目中,配置了 Umi
的 proxy
代理请求后端,发现接口返回并不是流式的逐渐输出,而是请求全部完成后一并输出了。。。
在排查过程中更改了下代码
js
const result = await fetch(`http://localhost:3000/stream`, { method: 'post' });
不使用代理直接去请求服务器,发现请求正常,变成了流式输出,把问题的范围缩小到了 proxy
这一层,既然项目采用了 Umi
, 那接下来就去 Github
搜索 SSE
相关的 issue
,得到如下结果:
进入第一个 issue
,发现问题确实出在 Umi
上,主要原因如该 issue
中所说:
官方已经在 4.1.5 版本修复了该问题。 接下来把 Umi
进行了升级,并修改 package.json
中的 script
脚本,添加了 UMI_DEV_SERVER_COMPRESS=none
这个环境变量:
json
"start": "cross-env UMI_ENV=dev UMI_DEV_SERVER_COMPRESS=none max dev",
重新启动项目后,请求已经变得正常,变为流式输出了。
与后端联调遇到的问题
在与后端联调中,发现业务请求又出现无法流式输出的情况了,后端中的测试请求接口却好使。经排查发现是因为返回的流式数据格式有问题,按规范修改后请求变得正常。数据格式参考如下:
部署到测试环境后遇到的问题
部署到测试环境后又不行了🤣。测试环境采用的 Nginx
和 uWIGS
,经过一系列百度之后发现这次的问题跟 Nginx
的配置有关系,SSE
相关的 Nginx
配置如下:
nginx.conf
proxy_pass http://your_backend;
proxy_http_version 1.1;
proxy_set_header Connection '';
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 86400s;
send_timeout 86400s;