使用 SSE 时不是流式输出而是等内容都输出完了一次性返回。
最近公司准备做个类似 GPT 一样的聊天功能,使用 SSE 来实现。 写了个 demo ,我在本机测试没问题,上了测试环境发现输出的内容都是等待后一次性输出到前端,并不是打字机的效果。
服务端代码如下:
@GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter c() {
SseEmitter sseEmitter = new SseEmitter();
log.error("xxx start");
//调用流式会话服务
new Thread(() -> streamChatCompletion(sseEmitter)).start();
log.error("xxx end");
//及时返回 SseEmitter 对象
return sseEmitter;
}
public void streamChatCompletion(SseEmitter emitter) {
try {
for (int i = 0; i < 3; i++) {
String o = "test" + i;
emitter.send(o);
Thread.sleep(1000); // 每秒发送一次
}
emitter.send(SseEmitter.event().name(" stop").data(""));
emitter.complete(); // 完成发送
} catch (IOException | InterruptedException e) {
emitter.completeWithError(e); // 发送错误
}
}
抓请求头 和 返回头吧
nginx 没配置吧,好像有个什么缓存的要关了
被网关缓存了,每一层网关都要检查
哈哈,上面 nginx 代理也有 sse 相关的配置的
public void demo( HttpServletResponse httpServletResponse) throws IOException {
httpServletResponse.setContentType("text/event-stream");
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setHeader("Cache-Control", "no-cache");
ServletOutputStream outputStream = httpServletResponse.getOutputStream();
while{
outputStream.write(("data: " + 字符串 + "\n\n").getBytes());
}
outputStream.write(("data: done\n\n").getBytes());
outputStream.flush();
} 查查 sse 的教程 www.ruanyifeng.com/blog/2017/05/server-sent_events.html
大概率 HTTP 版本低于 HTTP/1.1 。
Response Headers:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: null
Access-Control-Expose-Headers: permission, username, eagleeye-traceid
Connection: keep-alive
Content-Type: text/event-stream;charset=UTF-8
Date: Wed, 26 Feb 2025 02:00:08 GMT
Keep-Alive: timeout=4
Proxy-Connection: keep-alive
Server: f6car
Set-Cookie: romaSESSIONID=de1f56ef-5301-412a-8537-abe613dd1dc1; Path=/roma; HttpOnly
Vary: Origin
X-Application-Context: xx:test:8888
Request Headers:
GET /xx/sse/connect HTTP/1.1
Accept: text/event-stream
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: no-cache
DNT: 1
Host: report-pre.f6car.com
Origin: null
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36
GET /xx/sse/connect HTTP/1.1
Ngnix
proxy_ssl_verify off;
proxy_ssl_session_reuse off;
proxy_buffering off; # 禁用缓存谢谢大佬,我试试
大概率 nginx 的配置,网络链路上经过的中间件都排查下看看
nginx 的 proxy_buffering 配置,或者你响应头带一个 X-Accel-Buffering: no 也可以,详见 nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering
proxy_http_version 1.1;
# 设置 SSE 连接的超时时间,不设置默认是 2.5 分钟
proxy_read_timeout 86400s;
# 关闭缓冲
proxy_buffering off;
# 关闭代理缓存
proxy_cache off;
sse 这一个 proxy_buffering off;就好了,其它默认
谢谢大佬,加上这个响应头就可以了。
#12 ,响应头添加 X-Accel-Buffering: no ,这个方法更好
后端返回的流式输出效果不一定是平滑的,需要前端在做一层过滤来输出,这样才能达到平滑输出的效果。
我也做了这个需求,我在后端代码加多了 3 个响应头:
Content-Type: text/event-stream
Cache-Control: no-cache
X-Accel-Buffering: no
#18 这样更好,架构复杂了,ddos waf gateway lb ,所有环节添加 proxy_buffering 很不灵活
X-Accel-Buffering: no 就行。别去瞎改 nginx 配置。
下面这个图片来源国外,是一个关于程序员面试时的简历,被人事部门和程序员本身评审的角度不同的图片。当然,这是一个从国外面试的视角制作的图片,不过,可以看出,其中很多东西都是和国内…
懒得自己写一个node-ipc 事件后独立开发者的程序我都要完整审计一遍代码才敢在有重要数据的电脑上运行,更麻烦 sublime 开一个页面挂后台专门当记事本,临时代码、配置…
最近黑群晖弄起来了,但是在电视上看 NAS 里的 4k 蓝光原盘电影的时候特别卡,完全看不了 我测试的片源是一部 4k 蓝光原盘电影,大概 75G 左右 电视是红米 x75 2…
合速度