Skip to main content

umi 内置代理导致 sse 流失效

问题描述

在使用 umi 进行开发时,umi 内置代理导致 sse 流失效。
在接收到后端推送的消息时,接口会等待所有的消息流返回之后再将所有消息流一次涌出,导致 sse 消息流失去实时性,以及原本的意义。

原因分析

在 umi 中引用了@umijs/bundler-webpack,在@umijs/bundler-webpack中使用了compression中间件,导致了消息流的缓存。

对于compression的sse描述如下:
Server-Sent Events Because of the nature of compression this module does not work out of the box with server-sent events. To compress content, a window of the output needs to be buffered up in order to get good compression. Typically when using server-sent events, there are certain block of data that need to reach the client. You can achieve this by calling res.flush() when you need the data written to actually make it to the client.

地址:compression

app.use(require("@umijs/bundler-webpack/compiled/compression")());
拓展

compression 中间件是一个用于压缩响应的中间件,可以减少传输的数据量,提高传输速度。
nginx 也有可能会缓存对应的消息流,导致消息流失效。
也可能存在其他问题,待发现~ 对应sse实现方式,可以参考这里

解决方案

1. 配置对应环境变量在工程启动时候关闭compression中间件。 对应 issue

if (process.env.UMI_DEV_SERVER_COMPRESS !== "none") {
app.use(require("@umijs/bundler-webpack/compiled/compression")());
}

2. 不走本地代理,直接访问后端接口。

示例代码:

const ctrl = new AbortController();
const finish = () => {};
ctrl.signal.onabort = finish;
let remainText = "";

const fetchEvent = fetchEventSource("http://localhost:3000/api/stream", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(model),
signal: ctrl.signal,
});