SSE 技术简介
SSE(Server-Sent Events)是一种允许服务器主动向客户端推送数据的技术。它基于 HTTP 长连接,使用简单,特别适合实时数据更新场景,如股票行情、新闻推送等。与 WebSocket 相比,SSE 更轻量级,且只支持服务器到客户端的单向通信。
Spring Boot 集成 SSE
下面我将介绍如何在 Spring Boot 中实现 SSE 功能:
1. 添加依赖
首先在 pom.xml
中添加 Spring Web 依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2. 创建 SSE 控制器
以下是一个简单的 SSE 控制器示例,它可以定时向客户端推送消息:
package com.example.sse.demo.controller;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@RestController
public class SseController {
// 创建一个单线程的调度器
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
@GetMapping(path = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamSseMvc() {
SseEmitter emitter = new SseEmitter(60_000L); // 设置超时时间为60秒
// 启动定时任务,每秒发送一次消息
scheduler.scheduleAtFixedRate(() -> {
try {
// 发送数据
emitter.send(SseEmitter.event()
.id(String.valueOf(System.currentTimeMillis()))
.name("message")
.data("Hello, SSE! Time: " + System.currentTimeMillis()));
} catch (IOException e) {
// 发生异常时,完成发射器
emitter.completeWithError(e);
}
}, 0, 1, TimeUnit.SECONDS);
// 设置完成回调
emitter.onCompletion(() -> System.out.println("SSE connection completed"));
// 设置超时回调
emitter.onTimeout(() -> {
System.out.println("SSE connection timed out");
emitter.complete();
});
// 设置错误回调
emitter.onError((ex) -> {
System.out.println("SSE connection error: " + ex.getMessage());
emitter.completeWithError(ex);
});
return emitter;
}
}
3. 创建客户端页面
创建一个简单的 HTML 页面来接收服务器推送的消息:
<!DOCTYPE html>
<html>
<head>
<title>SSE Demo</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
#messages {
border: 1px solid #ccc;
padding: 10px;
margin-top: 10px;
height: 200px;
overflow-y: auto;
}
</style>
</head>
<body>
<h1>SSE Demo</h1>
<button onclick="startSse()">Start SSE</button>
<button onclick="stopSse()">Stop SSE</button>
<div id="messages"></div>
<script>
let eventSource;
function startSse() {
// 创建 EventSource 实例连接到服务器
eventSource = new EventSource('/sse');
// 监听 message 事件
eventSource.onmessage = function(event) {
const messagesDiv = document.getElementById('messages');
const newMessage = document.createElement('div');
newMessage.textContent = `[${new Date().toLocaleTimeString()}] ${event.data}`;
messagesDiv.appendChild(newMessage);
};
// 监听错误事件
eventSource.onerror = function(error) {
console.error('EventSource failed:', error);
const messagesDiv = document.getElementById('messages');
const errorMessage = document.createElement('div');
errorMessage.textContent = `Error: ${error}`;
errorMessage.style.color = 'red';
messagesDiv.appendChild(errorMessage);
// 关闭连接
eventSource.close();
};
}
function stopSse() {
if (eventSource) {
eventSource.close();
const messagesDiv = document.getElementById('messages');
const statusMessage = document.createElement('div');
statusMessage.textContent = 'Connection closed';
statusMessage.style.color = 'blue';
messagesDiv.appendChild(statusMessage);
}
}
</script>
</body>
</html>
运行和测试
- 启动 Spring Boot 应用
- 访问客户端页面(例如:
http://localhost:8080/index.html
) - 点击 “Start SSE” 按钮开始接收服务器推送的消息
- 点击 “Stop SSE” 按钮停止接收消息
关键技术点说明
服务器端:
- 使用
SseEmitter
处理 SSE 连接 - 设置适当的超时时间
- 实现错误处理和连接关闭逻辑
- 使用
MediaType.TEXT_EVENT_STREAM_VALUE
指定响应类型
- 使用
客户端:
- 使用
EventSource
对象连接到 SSE 服务器 - 监听
message
事件接收服务器推送的数据 - 监听
error
事件处理连接错误 - 使用
close()
方法关闭连接
- 使用
注意事项
- 生产环境中应考虑使用连接池和更健壮的错误处理机制
- 长时间运行的 SSE 连接可能需要处理网络中断和重连问题
- 考虑添加身份验证和授权机制保护 SSE 端点
- 对于大量并发连接,应评估服务器性能和资源消耗
通过以上步骤,你可以在 Spring Boot 应用中实现基本的 SSE 功能,实现服务器向客户端的实时数据推送。