Spring Boot 实战:SSE 实时通信方案设计与 WebSocket 深度对比

你点赞了吗?你关注了吗?每天分享干货好文。

高并发解决方案与架构设计。

海量数据存储和性能优化。

通用框架/组件设计与封装。

如何设计合适的技术架构?

如何成功转型架构设计与技术管理?

在竞争激烈的大环境下,只有不断提升核心竞争力才能立于不败之地。

公众号留言【我要晋级】,一对一指导,带你晋级。

一、实时通信技术选型:SSE vs WebSocket

在实时数据推送场景中(如股票行情、实时日志、消息通知),SSE(Server-Sent Events) 和 WebSocket 是最常用的两种方案。它们的核心差异如下:

特性

SSE

WebSocket

协议

基于 HTTP(单向)

基于 TCP(全双工)

数据格式

仅文本(UTF-8)

文本/二进制

连接方式

长连接,自动重连

持久化双向连接

浏览器兼容性

除 IE 外主流浏览器均支持

主流浏览器均支持

复杂度

低(无需额外协议)

高(需处理握手、心跳)

适用场景

服务器向客户端单向推送

双向实时交互(如聊天室)

二、SSE 核心原理
1. 通信流程
1. 客户端发起 HTTP 请求,Header 中指定 Accept: text/event-stream2. 服务器保持连接打开,持续发送事件流3. 数据格式为纯文本,按 event: data\n\n 分隔4. 客户端通过 EventSource API 接收并处理事件
2. 数据格式规范
// 单条事件event: priceUpdate\n    // 事件类型(可选)data: {"symbol":"BTC","price":50000}\n\n
// 多行数据data: 第一行内容\ndata: 第二行内容\n\n
// 重连时间(毫秒)retry: 3000\n\n

三、Spring Boot 服务端实现

1. 添加依赖
<!-- Spring Boot Web --><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId></dependency>
2. 创建 SSE 控制器
@RestController@RequestMapping("/sse")public class SseController {
    private static final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>();
    // 创建 SSE 连接    @GetMapping("/connect")    public SseEmitter connect(@RequestParam String clientId) {        SseEmitter emitter = new SseEmitter(60 * 60 * 1000L); // 超时时间1小时        emitters.put(clientId, emitter);
        emitter.onCompletion(() -> emitters.remove(clientId));        emitter.onTimeout(() -> emitters.remove(clientId));        emitter.onError((e) -> emitters.remove(clientId));
        return emitter;    }
    // 推送消息到指定客户端    @PostMapping("/send")    public void sendMessage(@RequestParam String clientId,                             @RequestParam String message) {        SseEmitter emitter = emitters.get(clientId);        if (emitter != null) {            try {                emitter.send(SseEmitter.event()                        .data(message)                        .id(UUID.randomUUID().toString())                        .reconnectTime(5000));            } catch (IOException e) {                emitters.remove(clientId);            }        }    }}
3. 模拟数据推送
@Scheduled(fixedRate = 3000)public void pushStockPrices() {    emitters.forEach((clientId, emitter) -> {        String price = "BTC: " + (50000 + new Random().nextInt(1000));        sendMessage(clientId, price);    });}

四、Vue 客户端实现

1. 创建 EventSource 连接
<template>  <div>    <h3>实时价格:</h3>    <div>{{ message }}</div>  </div></template>
<script>export default {  data() {    return {      message: '',      eventSource: null    };  },  mounted() {    this.connectSSE();  },  methods: {    connectSSE() {      const clientId = 'user_' + Math.random().toString(36).substr(2, 9);      this.eventSource = new EventSource(`http://localhost:8080/sse/connect?clientId=${clientId}`);
      this.eventSource.onmessage = (event) => {        this.message = event.data;      };
      this.eventSource.onerror = (error) => {        console.error('SSE 连接错误:', error);        // 自动重连        setTimeout(() => this.connectSSE(), 3000);      };    }  },  beforeUnmount() {    if (this.eventSource) {      this.eventSource.close();    }  }};</script>
2. 处理自定义事件类型
// 监听特定事件this.eventSource.addEventListener('priceUpdate', (event) => {  this.message = JSON.parse(event.data);});

五、与 WebSocket 的代码对比

1. WebSocket 服务端(Spring Boot)
@Configuration@EnableWebSocketpublic class WebSocketConfig implements WebSocketConfigurer {
    @Override    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {        registry.addHandler(new StockWebSocketHandler(), "/ws/stocks");    }
    class StockWebSocketHandler extends TextWebSocketHandler {        private List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
        @Override        public void afterConnectionEstablished(WebSocketSession session) {            sessions.add(session);        }
        @Override        protected void handleTextMessage(WebSocketSession session, TextMessage message) {            // 处理客户端消息(双向通信)            sessions.forEach(s -> s.sendMessage(message));        }    }}
2. WebSocket 客户端(Vue)
const socket = new WebSocket('ws://localhost:8080/ws/stocks');
socket.onmessage = (event) => {  this.message = event.data;};
// 发送消息到服务端socket.send('请求最新价格');

六、生产环境优化建议

1. SSE 优化
  • 心跳机制:定期发送注释行(:keepalive\n\n)防止连接超时

  • 负载均衡:使用 Nginx 配置 proxy_buffering off 避免缓冲

  • 安全加固:结合 JWT 验证客户端身份

2. WebSocket 优化
  • STOMP 协议:使用 STOMP over WebSocket 管理消息路由

  • 心跳检测:客户端/服务端定期发送 Ping/Pong 帧

  • 集群支持:通过 Redis Pub/Sub 实现多节点消息广播

七、总结:如何选择 SSE 和 WebSocket?

  • 选择 SSE 的场景

    • 只需服务器到客户端的单向推送

    • 要求快速实现、低复杂性

    • 兼容现有 HTTP 基础设施(如认证、防火墙)

  • 选择 WebSocket 的场景

    • 需要双向实时交互(如聊天、协作编辑)

    • 传输二进制数据(如文件、视频流)

    • 对延迟极度敏感(如在线游戏)

核心结论:SSE 是轻量级单向推送的首选,WebSocket 适合全双工复杂场景。根据业务需求合理选择,甚至可组合使用(如 SSE 推送通知,WebSocket 处理交互)。

架构设计之道在于在不同的场景采用合适的架构设计,架构设计没有完美,只有合适。

在代码的路上,我们一起砥砺前行。用代码改变世界!

精彩推荐>>>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值