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

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