SSE(Server-Sent Event) 介绍

前言

SSE(Server-Sent Events)是一种允许服务器向浏览器单向、持续推送数据的技术。

它的核心特点是 服务器推 。与传统的客户端请求、服务器响应的模式不同,SSE 建立连接后,服务器可以主动、多次地向客户端发送数据,直到连接关闭

一、SSE 是什么?有什么作用?

SSE 基于 HTTP 协议,使用简单,天生支持断线重连和事件标识 ,非常适合用于服务器向客户端单向推送实时更新的场景。

主要作用和应用场景:

  • 实时通知:如新消息提醒、订单状态更新。
  • 实时数据展示:如股票行情、体育比分、监控数据仪表盘。
  • AI 流式响应:这正是你之前代码处理的场景。大模型可以一边生成文本,一边通过 SSE 将结果片段推送给前端,实现"打字机"效果,用户体验极佳。
  • 日志实时输出:实时展示后台任务的执行日志。

与 WebSocket 的对比:

特性 SSE (Server-Sent Events) WebSocket
通信模式 单向 (服务器 → 客户端) 双向 (服务器 ⇌ 客户端)
协议 基于 HTTP/HTTPS 独立的 WS/WSS 协议
复杂度 简单,API 友好 相对复杂,需要处理连接、心跳等
适用场景 服务器推送为主,如通知、流式数据 需要高频双向交互,如在线游戏、聊天室

简单来说,如果只需要服务器向客户端推送数据,SSE 是更轻量、更简单的选择。


二、后端如何使用 (Spring Boot)

在 Spring Boot 中,实现 SSE 非常简单,核心是返回 SseEmitter 对象。

1. 创建 SSE 接口

创建一个 Controller,提供一个接口来建立 SSE 连接。

java 复制代码
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.ExecutorService;
import java.util.concurrent.Executors;

@RestController
public class SseController {

    // 使用线程池来异步发送数据,避免阻塞主线程
    private final ExecutorService executorService = Executors.newCachedThreadPool();

    @GetMapping(value = "/api/sse/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter stream() {
        // 1. 创建 SseEmitter 实例
        // 参数是超时时间,0L 表示永不过期
        SseEmitter emitter = new SseEmitter(0L);

        // 2. 在子线程中模拟数据推送
        executorService.execute(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    // 3. 发送数据
                    // 数据会被自动包装成 "data: {...}\n\n" 的格式
                    emitter.send(SseEmitter.event()
                            .name("message") // 可选:事件名称
                            .data("这是第 " + i + " 条消息"));

                    // 模拟耗时操作
                    Thread.sleep(1000);
                }
                // 4. 发送完成信号
                emitter.complete();
            } catch (IOException | InterruptedException e) {
                // 5. 发生异常时,通知客户端连接出错
                emitter.completeWithError(e);
            }
        });

        return emitter;
    }
}

代码解析:

  1. @GetMapping(..., produces = MediaType.TEXT_EVENT_STREAM_VALUE):
    • TEXT_EVENT_STREAM_VALUE 的值是 text/event-stream,这是 SSE 协议要求的 MIME 类型,告诉浏览器这是一个持续的数据流。
  2. SseEmitter emitter = new SseEmitter(0L):
    • 创建一个 SseEmitter 对象,它代表了与客户端的 SSE 连接。
    • 构造函数中的 0L 表示连接永不超时。默认是 30 秒,超时后连接会自动断开。
  3. emitter.send(...):
    • 这是推送数据的核心方法。你可以发送字符串、对象(会被自动序列化为 JSON)等。
    • SseEmitter.event() 是一个构建器,可以方便地设置事件名(name)、数据(data)和重连时间(reconnectTime)。
  4. emitter.complete():
    • 数据发送完毕后,调用此方法正常关闭连接。
  5. emitter.completeWithError(e):
    • 如果发生异常,调用此方法关闭连接并通知客户端。

2. 处理连接生命周期(可选但推荐)

你可以为 SseEmitter 添加回调,来处理连接超时、完成或出错的情况,便于进行资源清理或日志记录。

java 复制代码
// 在创建 emitter 后添加
emitter.onCompletion(() -> System.out.println("SSE 连接已完成"));
emitter.onTimeout(() -> {
    System.out.println("SSE 连接已超时");
    emitter.complete(); // 超时后手动关闭
});
emitter.onError((e) -> System.out.println("SSE 连接发生错误: " + e.getMessage()));

3. 广播消息(进阶)

如果需要向多个客户端推送同一条消息(如公告),可以使用一个集合来管理所有的 SseEmitter 实例。

java 复制代码
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

// ...

@RestController
public class BroadcastController {
    
    // 使用线程安全的集合存储所有活跃的 emitter
    private final Set<SseEmitter> emitters = ConcurrentHashMap.newKeySet();

    @GetMapping("/api/sse/subscribe")
    public SseEmitter subscribe() {
        SseEmitter emitter = new SseEmitter(0L);
        emitters.add(emitter);

        // 连接关闭时,从集合中移除
        emitter.onCompletion(() -> emitters.remove(emitter));
        emitter.onTimeout(() -> emitters.remove(emitter));
        emitter.onError((e) -> emitters.remove(emitter));

        return emitter;
    }

    // 模拟一个推送公告的接口
    @GetMapping("/api/admin/announce")
    public String announce(String message) {
        // 遍历所有 emitter,向每个客户端发送消息
        emitters.removeIf(emitter -> {
            try {
                emitter.send(message);
                return false; // 保留在集合中
            } catch (Exception e) {
                return true; // 发送失败,从集合中移除
            }
        });
        return "公告已推送";
    }
}

三、总结

SSE 是一个轻量级、基于 HTTP 的服务器推送技术,非常适合用于实时更新、通知和流式数据等场景。在 Spring Boot 中,通过 SseEmitter 可以非常方便地实现 SSE 功能,是处理服务器到客户端单向通信的绝佳选择。

相关推荐
PC2005_cloud37 分钟前
Windows 数据使用量页面卡死:1097 个热点档案和 161 MB 的 SRUM 库
前端·后端
u13013038 分钟前
GitHub 热榜项目:周榜(2026-09-20)
人工智能·github
烈风逍遥39 分钟前
AI大模型中fetch 和 ReadableStream为啥一起出现
前端·人工智能
袁俪43 分钟前
AI智能体 :
人工智能
Pioneer000011 小时前
我用 Redis + 网关做多模型 API 路由:缓存命中率 95%+ 的工程实践
人工智能·redis·后端·缓存·性能优化·架构
空奈qwq1 小时前
机器学习入门:从核心概念到建模全流程
人工智能·python·机器学习
半甜柠檬1 小时前
Claude Code支持AGENTS.md了_真正的重点藏在mods里
人工智能·ai助手
PC2005_cloud1 小时前
Nginx 防盗链配置实战:用 referer 模块保护网站静态资源
前端·后端