springboot+sse的实现案例

一 sse

1.1 介绍

SSE(Server-Sent Events,服务器发送事件)是一种基于 HTTP 的服务器向客户端单向推送实时数据 的技术,属于 HTML5 标准的一部分。它允许服务器主动向客户端发送数据流,适用于低延迟、单向实时更新的场景(如新闻推送、实时监控、日志流展示等)。

1和websocket对比

2.输出的数据格式:

1.2 遇到的问题案例

1.报错代码

SseEmitter emitter = new SseEmitter(300_000L*20)

emitter.send(SseEmitter.event().data(message));

2.nginx这样配置

location /bocai-chat {

proxy_send_timeout 3600s;

proxy_connect_timeout 1200s;

proxy_read_timeout 3600s;

proxy_buffering off;

proxy_pass http://bocaicluster/bocai-chat;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}

3.这段代码提示报

org.springframework.web.context.request.async.AsyncRequestNotUsableException: ServletOutputStream failed to flush: java.io.IOException: Connection reset by peer

4.前端页面通过nginx代理访问且并没有刷新关闭页面,通过nginx代理后的页面访问报这个错误,直接绕过nginx返回后端服务程序是正常。最后排查的是nginx代理的后端负载服务器存在问题。

二 sse的案例

2.1 两种情况的说明

2.2 同步阻塞-发送数据

说明:同步阻塞:能发送数据,但无法触发onCompletion回调的执行。

因为同步阻塞,发送send,complete方法后,emitter.onCompletion()还没有注册。无法触发。

同时如果浏览器关闭,send发送也不会触发异常。

1.代码

复制代码
 /**
     * @author admin
     * @description      同步阻塞
     * @date 2025/12/20 12:39
     * @param []
     * @return org.springframework.web.servlet.mvc.method.annotation.SseEmitter
     */
    @GetMapping("/stream3")
    public SseEmitter streamDataCallBack() {
        SseEmitter emitter = new SseEmitter(300000L); // 0表示不超时
        // 设置完成和超时回调
        emitter.onCompletion(() -> System.out.println("完成.."));
        emitter.onTimeout(() -> {
                    System.out.println("超时...");
                    emitter.complete(); // 超时后主动完成
                }
        );
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
            // 发送初始连接成功消息
            try {
                emitter.send(SseEmitter.event()
                        .name("CONNECTED")
                        .data("{\"status\": \"connected\", \"timestamp\": \"" +
                                System.currentTimeMillis() + "\"}"));
//              .data("你好当前是:"+System.currentTimeMillis()));
            } catch (Exception e) {
                System.out.println("报异常了:"+e);
                emitter.completeWithError(e);
            }
        try {
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("正常....");
            emitter.complete(); // 此时回调已注册,会触发 onCompletion
        return emitter;
    }

2.效果图

控制台:

2.3 异步非阻塞-发送数据

1.能够触发,oncompletion的方法。加了异步处理

复制代码
 /**
    * @author admin
    * @description       正常场景
    * @date 2025/12/20 12:39
    * @param []
    * @return org.springframework.web.servlet.mvc.method.annotation.SseEmitter
    */
    @GetMapping("/stream")
    public SseEmitter streamData() {
        SseEmitter emitter = new SseEmitter(0L); // 0表示不超时

        // 将新的emitter添加到集合中
       // emitters.add(emitter);

        // 设置完成和超时回调
        emitter.onCompletion(() -> System.out.println("完成.."));
        emitter.onTimeout(() -> {
                    System.out.println("超时...");
                    emitter.complete(); // 超时后主动完成
                }
        );
        executor.schedule(() -> {
        // 发送初始连接成功消息
        try {
            emitter.send(SseEmitter.event()
                    .name("CONNECTED")
                    .data("{\"status\": \"connected\", \"timestamp\": \"" +
                            System.currentTimeMillis() + "\"}"));
//              .data("你好当前是:"+System.currentTimeMillis()));
        } catch (IOException e) {
            System.out.println("报异常了:"+e);
            emitter.completeWithError(e);
        }
            System.out.println("正常....");
            emitter.complete(); // 此时回调已注册,会触发 onCompletion
        }, 50, TimeUnit.SECONDS);
//       emitter.complete();
        return emitter;
    }

2.效果

2.4 异步非阻塞-正常发送数据-关闭浏览器

1.在浏览器输入地址访问:大概10s后,关闭浏览器

2.后端设置了延迟50s,在50s后开始执行,发现客户端已经断开,报错

2.5 异步非阻塞-超时

1.设置超时小一点,业务执行长一点;200毫秒肯定小于1秒

2.执行效果

控制台:看到触发超时回调方法

相关推荐
CV工程师丁Sir1 小时前
ArkWeb 手记 04|DevTools 调试与缓存清理
java·spring·缓存·harmonyos
光依旧7 小时前
MCP实战手记系列(十):MCP Server高可用实战
spring boot·高可用·nginx负载均衡·redis哨兵·mcp·微服务容错·resilience4j熔断
Sarvartha7 小时前
final 关键字
java·开发语言
2601_952047797 小时前
单一策略深度教程:用轻易云把集成任务的报错实时推送到钉钉机器人
java·机器人·钉钉
数据狐(Datafox)8 小时前
淘宝图片搜索 API 落地实战:基于以图搜货搭建跨境电商选品系统
java·大数据·微服务
刚子编程10 小时前
我用 ASP.NET Core 做了个水稻病虫害检查系统
后端·asp.net
谢亮_vipxieliang10 小时前
用 PHP 构建轻量级 REST API:从路由到鉴权的完整实践
开发语言·后端·php
Escalating_xu10 小时前
【C 语言】数据在内存中的存储:补码、大小端、整型陷阱与 IEEE 754 全解析
java·c语言·网络