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

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

相关推荐
Remember_99311 小时前
Java 单例模式深度解析:设计原理、实现范式与企业级应用场景
java·开发语言·javascript·单例模式·ecmascript
代码or搬砖11 小时前
ReentranLock中AQS讲解
java·开发语言·redis
rainbow688911 小时前
C++智能指针实战:从入门到精通
java·开发语言
HalvmånEver11 小时前
Linux:进程 vs 线程:资源共享与独占全解析(线程四)
java·linux·运维
qq_124987075311 小时前
基于springboot的竞赛团队组建与管理系统的设计与实现(源码+论文+部署+安装)
java·vue.js·spring boot·后端·信息可视化·毕业设计·计算机毕业设计
瑞雪兆丰年兮11 小时前
[从0开始学Java|第五天]Java循环高级综合练习
java·开发语言
J_liaty11 小时前
SpringBoot 自定义注解实现接口加解密:一套完整的多算法方案
java·spring boot·算法
Dr.Kun11 小时前
【鲲码园PsychoPy】Go/No-go范式
开发语言·后端·golang
zhengfei61111 小时前
踪有趣的 Linux(和 UNIX)恶意软件。提交 PR
java·数据库·mysql
「QT(C++)开发工程师」11 小时前
C++ 观察者模式
java·c++·观察者模式