Event Stream 是一种允许服务器推送事件到客户端的技术。在 Web 开发中,最常见的实现方式就是 Server-Sent Events (SSE)。
本文将介绍如何使用 Vue 和 Spring Boot 实现基于 Server-Sent Events (SSE) 的 Event Stream 技术。
1. 什么是 Event Stream 和 SSE?
Event Stream 是一种允许服务器推送事件到客户端的技术。与传统的 AJAX 请求不同,SSE 是服务器主动向客户端发送数据流,客户端可以无需反复请求实时接收更新。
主要特点:
- 单向通信:服务器向客户端推送数据,但客户端不能通过同一连接发送数据回服务器。
- 基于 HTTP 协议:SSE 使用标准的 HTTP 协议,使用
text/event-stream
内容类型进行数据传输。
- 持久连接:客户端与服务器之间保持长期连接,服务器可以实时的将数据推送给客户端。
2. 为什么使用 SSE?
与 WebSocket 和轮询相比,SSE 更简单,性能更高:
- WebSocket 需要双向通信,适用于复杂的双向实时通信场景。
- 轮询 需要不断请求服务器,增加了不必要的网络流量和延迟。
- SSE 是单向的,只适合服务器推送数据到客户端,非常适用于通知、实时更新等场景,且性能和延迟更低。
3. Vue实现Event Stream
为方便使用封装工具函数sse.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
export function createSseConnection(url, { onMessage, onError, onOpen }) { const eventSource = new EventSource(url);
if (onOpen) { eventSource.onopen = () => { console.log('SSE connection established'); onOpen(); }; }
if (onMessage) { eventSource.onmessage = (event) => { onMessage(event.data); }; }
if (onError) { eventSource.onerror = (error) => { console.error('SSE connection error', error); onError(error); eventSource.close(); }; }
return eventSource; }
export function closeSseConnection(eventSource) { if (eventSource) { eventSource.close(); console.log('SSE connection closed'); } }
|
在Vue组件中使用该函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| <template> <div> <h1>实时数据推送</h1> <div v-if="message"> <p>服务器推送的数据:{{ message }}</p> </div> <button @click="closeConnection">关闭连接</button> </div> </template>
<script> import { createSseConnection, closeSseConnection } from '@/utils/sse';
export default { data() { return { message: null, eventSource: null, }; }, created() { // 使用封装的工具函数建立 SSE 连接 this.eventSource = createSseConnection('http://localhost:8080/api/events', { onMessage: (data) => { this.message = data; }, onError: (error) => { alert('连接错误'); console.error(error); }, onOpen: () => { console.log('SSE 连接成功'); } }); }, methods: { // 关闭 SSE 连接 closeConnection() { closeSseConnection(this.eventSource); this.message = '连接已关闭'; } }, beforeDestroy() { // 在组件销毁时关闭 SSE 连接,避免内存泄漏 if (this.eventSource) { closeSseConnection(this.eventSource); } } }; </script>
|
4. Spring Boot 实现 Event Stream
使用 Spring Boot 提供的 SseEmitter 来实现 SSE。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 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;
@RestController public class EventStreamController {
@GetMapping("/api/events") public SseEmitter streamEvents() { SseEmitter emitter = new SseEmitter(); new Thread(() -> { try { for (int i = 0; i < 10; i++) { emitter.send("实时数据:" + i); Thread.sleep(1000); } emitter.complete(); } catch (IOException | InterruptedException e) { emitter.completeWithError(e); } }).start();
return emitter; } }
|
6. 注意
- 连接数限制: 每个客户端都会占用一个HTTP长链接,需要注意服务器并发能力。
- 数据格式和传输内容: SSE 默认采用文本格式传输数据,数据内容尽量简洁,避免发送过多的二进制数据或复杂的结构。
7. SSE 与 WebSocket 的对比
虽然 SSE 是一个很好的单向推送解决方案,但它与 WebSocket 在某些场景下有所区别:
SSE 适用于单向通信,简单实现,适合推送实时更新数据(如新闻更新、社交网络动态)。
WebSocket 适用于双向实时通信,支持更复杂的互动场景(如聊天室、多人在线游戏、即时消息传递等)。