1. 什么是SSE技术SSEServer-Sent Events是一种基于HTTP协议的服务器推送技术它允许服务器单向地向客户端通常是浏览器发送实时数据更新。想象一下你正在看一场体育比赛的实时比分直播比分变化时页面会自动刷新这就是SSE的典型应用场景。与WebSocket不同SSE是单向通信——数据只能从服务器流向客户端。这种特性让它特别适合以下场景后台任务进度通知比如文件上传进度实时数据监控面板服务器性能指标、股票行情新闻推送或社交媒体更新简单的聊天应用只需要接收消息我在实际项目中使用SSE的经历很能说明问题。去年我们有个客户需要实时监控服务器集群状态最初考虑用WebSocket但发现客户端只需要接收数据不需要发送复杂指令。改用SSE后开发周期缩短了40%而且运行更稳定。2. SpringBoot中配置SSE2.1 基础环境搭建首先创建一个标准的SpringBoot项目只需要添加最基本的web依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency这里有个小技巧建议使用SpringBoot 2.2版本它对异步处理做了优化。我在使用2.1.8版本时遇到过连接不稳定的问题升级后完美解决。2.2 核心控制器实现创建一个简单的控制器来处理SSE连接RestController RequestMapping(/sse) public class SseController { GetMapping(path /connect, produces MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter connect() { SseEmitter emitter new SseEmitter(30_000L); // 30秒超时 // 发送欢迎消息 try { emitter.send(SseEmitter.event() .name(welcome) .data(连接成功当前时间 LocalTime.now())); } catch (IOException e) { emitter.completeWithError(e); } // 模拟定时发送数据 Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() - { try { emitter.send(SseEmitter.event() .data(心跳检测 LocalTime.now())); } catch (Exception e) { emitter.completeWithError(e); } }, 1, 1, TimeUnit.SECONDS); // 连接关闭处理 emitter.onCompletion(() - System.out.println(连接关闭)); emitter.onTimeout(() - System.out.println(连接超时)); return emitter; } }这段代码有几个关键点produces MediaType.TEXT_EVENT_STREAM_VALUE声明这是一个SSE端点SseEmitter的超时时间根据业务需求设置使用单独的线程池发送数据避免阻塞主线程3. 前端集成EventSource前端集成非常简单现代浏览器都原生支持EventSource API!DOCTYPE html html body div idmessages/div script const eventSource new EventSource(/sse/connect); eventSource.addEventListener(welcome, function(e) { console.log(欢迎消息:, e.data); document.getElementById(messages).innerHTML e.data br; }); eventSource.onmessage function(e) { console.log(收到消息:, e.data); document.getElementById(messages).innerHTML e.data br; }; eventSource.onerror function() { console.error(连接出错5秒后重试...); setTimeout(() new EventSource(/sse/connect), 5000); }; /script /body /html实际项目中我发现几个有用的技巧为不同类型的事件添加不同的事件监听器如上面的welcome错误处理中实现自动重连在页面卸载时记得关闭连接window.onbeforeunload () eventSource.close();4. 高级功能实现4.1 多客户端管理实际项目中我们需要管理多个客户端连接。下面是一个增强版的实现Service public class SseService { private final MapString, SseEmitter emitters new ConcurrentHashMap(); public SseEmitter subscribe(String clientId) { SseEmitter emitter new SseEmitter(60_000L); emitters.put(clientId, emitter); emitter.onCompletion(() - emitters.remove(clientId)); emitter.onTimeout(() - emitters.remove(clientId)); return emitter; } public void sendToClient(String clientId, Object data) { SseEmitter emitter emitters.get(clientId); if (emitter ! null) { try { emitter.send(data); } catch (IOException e) { emitter.completeWithError(e); } } } public void broadcast(Object data) { emitters.forEach((id, emitter) - { try { emitter.send(data); } catch (IOException e) { emitter.completeWithError(e); } }); } }4.2 异常处理与重连机制SSE连接可能因为网络问题中断完善的异常处理很重要ControllerAdvice public class SseExceptionHandler { ExceptionHandler public void handleIOException(IOException e, HttpServletResponse response) { response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value()); // 记录日志 System.err.println(SSE连接异常: e.getMessage()); } }前端可以这样增强健壮性function connectSSE() { const es new EventSource(/sse/connect); es.onerror () { es.close(); setTimeout(connectSSE, 3000); // 3秒后重连 }; return es; } const eventSource connectSSE();5. SSE与WebSocket的对比选择SSE和WebSocket各有优劣这里是我的经验总结特性SSEWebSocket通信方向单向服务器→客户端双向协议HTTP独立协议实现复杂度简单较复杂浏览器支持除IE外主流都支持现代浏览器都支持适用场景实时通知、监控聊天、协作编辑选择建议只需要服务器推送优先考虑SSE需要双向交互选择WebSocket需要支持IE考虑长轮询或WebSocket6. 性能优化实战技巧经过多个项目实践我总结出这些优化经验连接管理设置合理的超时时间30-120秒及时清理断开连接的Emitter使用UUID作为客户端标识数据格式优化使用JSON格式传输结构化数据压缩大体积数据避免频繁发送小数据合并发送服务器配置# application.properties server.servlet.session.timeout60s spring.mvc.async.request-timeout60000监控指标RestController public class SseMetricsController { Autowired private SseService sseService; GetMapping(/sse/stats) public MapString, Object getStats() { return Map.of( activeConnections, sseService.getConnectionCount(), lastBroadcastTime, sseService.getLastBroadcastTime() ); } }7. 真实案例任务进度通知系统去年我们为某云平台开发的任务中心就使用了SSE。核心需求是用户提交长时间运行的任务如数据导出实时显示任务进度任务完成时通知用户实现代码片段PostMapping(/export) public ResponseEntityString startExport(RequestBody ExportRequest request) { String taskId UUID.randomUUID().toString(); // 启动异步任务 CompletableFuture.runAsync(() - { SseEmitter emitter sseService.subscribe(taskId); try { for (int i 0; i 100; i 10) { Thread.sleep(1000); emitter.send( new ProgressUpdate(i, 处理中...) ); } emitter.send(new ProgressUpdate(100, 完成)); emitter.complete(); } catch (Exception e) { emitter.completeWithError(e); } }); return ResponseEntity.ok(taskId); }前端通过taskId订阅专属进度通道const taskId await startExport(); const es new EventSource(/sse/progress?taskId${taskId}); es.onmessage e { const progress JSON.parse(e.data); updateProgressBar(progress.percent); if (progress.percent 100) { es.close(); } };这个方案上线后用户对实时进度反馈非常满意客服咨询量下降了35%。