V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
rainfy
V2EX  ›  Java

使用 SSE 时不是流式输出而是等内容都输出完了一次性返回。

  •  
  •   rainfy · 19 小时 59 分钟前 · 1819 次点击
    最近公司准备做个类似 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); // 发送错误
    }
    }
    20 条回复    2025-02-26 15:34:45 +08:00
    guanhui07
        1
    guanhui07  
       19 小时 52 分钟前
    抓请求头 和 返回头吧
    xxkuboy
        2
    xxkuboy  
       19 小时 52 分钟前
    nginx 没配置吧,好像有个什么缓存的要关了
    kerb15
        3
    kerb15  
       19 小时 50 分钟前
    被网关缓存了,每一层网关都要检查
    xuelang
        4
    xuelang  
       19 小时 48 分钟前
    哈哈,上面 nginx 代理也有 sse 相关的配置的
    magicZ
        5
    magicZ  
       19 小时 45 分钟前
    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 的教程 https://www.ruanyifeng.com/blog/2017/05/server-sent_events.html
    jaylee4869
        6
    jaylee4869  
       19 小时 34 分钟前
    大概率 HTTP 版本低于 HTTP/1.1 。
    rainfy
        7
    rainfy  
    OP
       19 小时 32 分钟前
    @guanhui07
    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
    rainfy
        8
    rainfy  
    OP
       19 小时 31 分钟前
    @jaylee4869 GET /xx/sse/connect HTTP/1.1
    CHTuring
        9
    CHTuring  
       19 小时 21 分钟前
    Ngnix

    ```
    proxy_ssl_verify off;
    proxy_ssl_session_reuse off;
    proxy_buffering off; # 禁用缓存
    ```
    rainfy
        10
    rainfy  
    OP
       19 小时 19 分钟前
    @CHTuring 谢谢大佬,我试试
    yevXxHmg
        11
    yevXxHmg  
       19 小时 12 分钟前
    大概率 nginx 的配置,网络链路上经过的中间件都排查下看看
    yanjieee
        12
    yanjieee  
       18 小时 58 分钟前   ❤️ 2
    nginx 的 proxy_buffering 配置,或者你响应头带一个 X-Accel-Buffering: no 也可以,详见 https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering
    weenhall5
        13
    weenhall5  
       18 小时 54 分钟前
    proxy_http_version 1.1;
    # 设置 SSE 连接的超时时间,不设置默认是 2.5 分钟
    proxy_read_timeout 86400s;
    # 关闭缓冲
    proxy_buffering off;
    # 关闭代理缓存
    proxy_cache off;
    salmon5
        14
    salmon5  
       18 小时 47 分钟前
    sse 这一个 proxy_buffering off;就好了,其它默认
    rainfy
        15
    rainfy  
    OP
       18 小时 36 分钟前
    @yanjieee 谢谢大佬,加上这个响应头就可以了。
    salmon5
        16
    salmon5  
       16 小时 36 分钟前
    @yanjieee #12 ,响应头添加 X-Accel-Buffering: no ,这个方法更好
    foolyf
        17
    foolyf  
       15 小时 0 分钟前
    后端返回的流式输出效果不一定是平滑的,需要前端在做一层过滤来输出,这样才能达到平滑输出的效果。
    SoulFlame
        18
    SoulFlame  
       14 小时 53 分钟前   ❤️ 1
    我也做了这个需求,我在后端代码加多了 3 个响应头:
    Content-Type: text/event-stream
    Cache-Control: no-cache
    X-Accel-Buffering: no
    salmon5
        19
    salmon5  
       14 小时 11 分钟前
    @SoulFlame #18 这样更好,架构复杂了,ddos waf gateway lb ,所有环节添加 proxy_buffering 很不灵活
    lambdaq
        20
    lambdaq  
       14 小时 9 分钟前
    X-Accel-Buffering: no 就行。别去瞎改 nginx 配置。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   998 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 21:43 · PVG 05:43 · LAX 13:43 · JFK 16:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.