使用Spring Boot实现Server-Sent Events(SSE)实时推送

使用Spring Boot实现Server-Sent Events(SSE)实时推送

什么是SSE?

Server-Sent Events(SSE) 是一种基于HTTP的服务器向客户端单向实时推送数据的技术。与WebSocket不同,SSE仅支持服务器到客户端的单向通信,适用于实时通知、股票行情、新闻推送等场景。

核心特性:

  • 基于HTTP协议,兼容现有基础设施
  • 支持自动重连
  • 轻量级,使用简单
  • 默认支持文本数据格式

一、快速搭建Spring Boot SSE服务

1. 创建项目

通过Spring Initializr创建项目,选择依赖:

  • Spring Web(用于Web端点)

2. 实现SSE控制器

java 复制代码
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

@RestController
public class SSEController {

    private final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>();

    // 客户端连接端点
    @GetMapping(path = "/connect", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter connect(@RequestParam String userId) {
        SseEmitter emitter = new SseEmitter(60_000L); // 超时时间60秒
        
        // 注册清理回调
        emitter.onCompletion(() -> emitters.remove(userId));
        emitter.onTimeout(() -> emitters.remove(userId));
        
        emitters.put(userId, emitter);
        return emitter;
    }

    // 消息推送方法(可在Service中调用)
    public void sendEvent(String userId, String message) {
        SseEmitter emitter = emitters.get(userId);
        if (emitter != null) {
            try {
                emitter.send(SseEmitter.event()
                        .data(message)
                        .name("custom-event")); // 自定义事件名称
            } catch (IOException e) {
                emitters.remove(userId);
            }
        }
    }
}

二、客户端实现

HTML页面示例:

html 复制代码
<!DOCTYPE html>
<html>
<body>
    <div id="messages"></div>
    <script>
        const eventSource = new EventSource('http://localhost:8080/connect?userId=123');
        
        // 监听默认消息
        eventSource.onmessage = (e) => {
            document.getElementById('messages').innerHTML += e.data + '<br>';
        };

        // 监听自定义事件
        eventSource.addEventListener('custom-event', (e) => {
            console.log('Custom event:', e.data);
        });
    </script>
</body>
</html>

三、进阶功能实现

1. 广播消息

java 复制代码
public void broadcast(String message) {
    emitters.forEach((id, emitter) -> {
        try {
            emitter.send(message);
        } catch (IOException e) {
            emitters.remove(id);
        }
    });
}

2. 发送结构化数据(JSON)

java 复制代码
emitter.send(SseEmitter.event()
        .data(new MyDataObject("value"), MediaType.APPLICATION_JSON)
        .id("event-123")
        .reconnectTime(5000));

3. 心跳机制(防止连接超时)

java 复制代码
@Scheduled(fixedRate = 30_000)
public void sendHeartbeat() {
    emitters.forEach((id, emitter) -> {
        try {
            emitter.send(SseEmitter.event().comment("heartbeat"));
        } catch (IOException ignored) {}
    });
}

四、注意事项

  1. 连接管理

    • 使用ConcurrentHashMap存储连接
    • 及时移除已关闭的连接
    • 设置合理的超时时间(默认:30秒)
  2. 跨域问题

    java 复制代码
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/connect")
                    .allowedOrigins("*");
        }
    }
  3. 性能优化

    • 调整Tomcat线程池配置
    • 考虑使用异步处理(@Async

五、SSE vs WebSocket

特性 SSE WebSocket
协议 HTTP WS/TCP
通信方向 单向(服务器→客户端) 双向
数据格式 Text/Event-Stream 二进制/自定义
自动重连 支持 需手动实现
浏览器兼容性 除IE外主流浏览器 现代浏览器

总结

SSE是实现服务器推送的高效解决方案,适用于需要实时更新但不需要双向通信的场景。结合Spring Boot的SseEmitter,开发者可以快速构建实时功能。完整示例代码已上传至GitHub仓库

扩展阅读:


通过本文,读者可以快速掌握SSE的核心实现,并根据实际需求扩展功能。建议根据具体场景选择合适的实时通信方案。

相关推荐
牛奔37 分钟前
Go 如何避免频繁抢占?
开发语言·后端·golang
想用offer打牌6 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
KYGALYX7 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
爬山算法8 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端