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.执行效果

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

相关推荐
上海合宙LuatOS5 小时前
LuatOS核心库API——【audio 】
java·网络·单片机·嵌入式硬件·物联网·音视频·硬件工程
汤姆yu5 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
TT哇5 小时前
【实习】银行经理端线下领取扫码功能实现方案
java
暮色妖娆丶5 小时前
Spring 源码分析 单例 Bean 的创建过程
spring boot·后端·spring
野犬寒鸦5 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
黎雁·泠崖5 小时前
【魔法森林冒险】2/14 抽象层设计:Figure/Person类(所有角色的基石)
java·开发语言
Java编程爱好者5 小时前
Seata实现分布式事务:大白话全剖析(核心讲透AT模式)
后端
神奇小汤圆5 小时前
比MySQL快800倍的数据库:ClickHouse的性能秘密
后端
小小张说故事6 小时前
BeautifulSoup:Python网页解析的优雅利器
后端·爬虫·python
怒放吧德德6 小时前
后端 Mock 实战:Spring Boot 3 实现入站 & 出站接口模拟
java·后端·设计