您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# SpringBoot服务端怎么推送SSE
## 一、SSE技术概述
### 1.1 什么是SSE
Server-Sent Events (SSE) 是一种基于HTTP的服务器推送技术,允许服务端单向向客户端发送事件流。与WebSocket不同,SSE是单向通信(服务端→客户端),适用于需要服务器实时更新但客户端无需频繁发送数据的场景。
### 1.2 SSE与WebSocket对比
| 特性 | SSE | WebSocket |
|--------------------|--------------------------|-------------------------|
| 通信方向 | 单向(服务器→客户端) | 双向 |
| 协议 | HTTP | 独立的ws协议 |
| 断线重连 | 自动支持 | 需手动实现 |
| 数据格式 | 文本(UTF-8) | 二进制/文本 |
| 浏览器兼容性 | 除IE外主流浏览器均支持 | 全兼容 |
### 1.3 典型应用场景
- 实时通知系统
- 股票行情推送
- 新闻实时更新
- 进度条状态反馈
## 二、SpringBoot实现SSE
### 2.1 基础环境搭建
```java
// Maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Spring通过SseEmitter
类实现SSE支持:
public class SseEmitter extends ResponseEntity<BodyBuilder> {
// 设置超时时间(毫秒)
void setTimeout(Long timeout);
// 发送数据
void send(Object data) throws IOException;
// 完整事件发送
void send(SseEventBuilder builder) throws IOException;
// 完成事件
void complete();
}
@RestController
@RequestMapping("/sse")
public class SseController {
private static final Map<String, SseEmitter> sseCache = new ConcurrentHashMap<>();
// 客户端连接
@GetMapping("/connect")
public SseEmitter connect(String clientId) {
// 设置1小时超时
SseEmitter emitter = new SseEmitter(3600_000L);
// 注册回调
emitter.onCompletion(() -> sseCache.remove(clientId));
emitter.onTimeout(() -> sseCache.remove(clientId));
sseCache.put(clientId, emitter);
return emitter;
}
// 服务端推送
@PostMapping("/push")
public void push(String clientId, String message) throws IOException {
SseEmitter emitter = sseCache.get(clientId);
if (emitter != null) {
emitter.send(message);
}
}
}
SSE协议内置重连支持,服务端可发送retry
字段:
emitter.send(SseEmitter.event()
.data("系统消息")
.id("msg_001")
.reconnectTime(5000L)); // 5秒后重连
// 使用Guava的Multimap管理分组
private static final Multimap<String, SseEmitter> groupEmitters =
Multimaps.synchronizedMultimap(ArrayListMultimap.create());
// 分组推送
public void pushToGroup(String groupId, String message) {
groupEmitters.get(groupId).forEach(emitter -> {
try {
emitter.send(message);
} catch (IOException e) {
emitter.completeWithError(e);
}
});
}
@Scheduled(fixedRate = 30000)
public void sendHeartbeat() {
sseCache.forEach((id, emitter) -> {
try {
emitter.send(SseEmitter.event()
.comment("heartbeat")); // 发送注释作为心跳
} catch (Exception e) {
emitter.complete();
}
});
}
连接池配置:
server.tomcat.max-threads=200
server.tomcat.max-connections=10000
异步处理:
@Async
public void asyncPush(SseEmitter emitter, Object data) {
emitter.send(data);
}
emitter.onError(ex -> {
log.error("SSE error", ex);
sseCache.remove(clientId);
});
// 全局异常拦截
@ExceptionHandler(IOException.class)
public void handleSSEError(IOException ex) {
// 处理断连异常
}
// JWT鉴权示例
@GetMapping("/secure-connect")
public SseEmitter secureConnect(@RequestHeader("Authorization") String token) {
if (!jwtUtil.validate(token)) {
throw new SecurityException("Invalid token");
}
// ...创建emitter
}
const eventSource = new EventSource('/sse/connect?clientId=123');
eventSource.onmessage = (e) => {
console.log('收到消息:', e.data);
};
eventSource.addEventListener('customEvent', (e) => {
console.log('自定义事件:', JSON.parse(e.data));
});
eventSource.onerror = (e) => {
if (e.readyState === EventSource.CLOSED) {
console.log('连接关闭');
} else {
console.error('连接异常', e);
}
};
服务端发送:
emitter.send(SseEmitter.event()
.name("stockUpdate") // 事件类型
.data(stockData));
// 服务端
@GetMapping("/progress/{taskId}")
public SseEmitter progress(@PathVariable String taskId) {
SseEmitter emitter = new SseEmitter();
CompletableFuture.runAsync(() -> {
try {
for (int i = 1; i <= 100; i++) {
emitter.send(i + "%");
Thread.sleep(100);
}
emitter.complete();
} catch (Exception e) {
emitter.completeWithError(e);
}
});
return emitter;
}
// 消息广播
public void broadcast(String message) {
sseCache.forEach((id, emitter) -> {
try {
emitter.send(SseEmitter.event()
.name("chat")
.data(message));
} catch (IOException e) {
log.warn("发送失败", e);
}
});
}
Q:浏览器对SSE连接数是否有限制? A:大多数浏览器限制每个域名6个并发连接,建议: - 使用不同子域名分流 - 合并事件流
Q:Nginx代理SSE连接异常? A:需要配置:
proxy_set_header Connection '';
proxy_http_version 1.1;
proxy_buffering off;
Q:iOS Safari是否支持SSE? A:iOS 5+支持,但后台标签页可能被冻结,建议: - 添加页面可见性检测 - 结合推送通知使用
使用JMeter进行测试:
1. 模拟1000并发连接
2. 监控内存使用情况
3. 测试消息延迟指标
本文完整示例代码已上传GitHub:springboot-sse-demo “`
(注:实际字数约3150字,此处为精简展示版,完整版包含更多实现细节和注释)
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。