1. 简介
Server-Sent Events(简称SSE)是一种允许服务器主动向客户端(如浏览器)推送信息的技术。它是HTML5规范的一部分,提供了一种单向通信机制,使得服务器可以实时向客户端发送数据更新。
关键点:
-
基本概念:
-
SSE基于HTTP协议,通过创建一个到服务器的持久连接来实现数据的实时推送。
-
客户端通过JavaScript的
EventSource
接口与服务器建立连接,并监听服务器发送的事件。
-
-
特点:
-
单向通信:SSE只支持服务器到客户端的单向通信,如果需要双向通信,则可能需要使用WebSocket。
-
简单易用:相比于WebSocket,SSE的使用更简单,对服务器端的改动也较小。
-
断线重连:SSE默认支持断线重连,当连接中断时,客户端会自动尝试重新连接。
-
-
使用场景:
-
实时消息通知,如新闻更新、股票价格变动等。
-
实时数据更新,如仪表板数据显示、在线协作工具等。
-
聊天室或社交媒体的实时更新。
-
-
客户端API:
-
EventSource
对象用于创建和服务器的连接,并监听服务器发送的事件。 -
onmessage
事件处理器用于处理服务器发送的数据。 -
onerror
事件处理器用于处理连接错误。
-
-
服务器端实现:
-
服务器需要设置响应头
Content-Type: text/event-stream
,以表明发送的是事件流。 -
服务器可以按照规定的格式发送数据,包括
data
、event
、id
和retry
字段。
-
-
数据格式:
-
SSE数据流是由多个消息组成,每个消息由多个字段组成,字段之间用换行符分隔。
-
例如:
data: some text\n\n
表示一个数据字段,event: usermessage\ndata: {"username": "bobby", "age": "22"}\n\n
表示一个命名事件。
-
-
注意事项:
-
为了保证数据的完整性,服务器发送的消息应该包含
id
字段,以便客户端在重连时可以从最后一个接收到的事件ID继续接收数据。 -
SSE连接可能会受到HTTP/1.1的6个连接限制,但HTTP/2可以协商更高的连接数(默认100)。
-
-
兼容性:
-
SSE在现代浏览器中得到了广泛支持,但IE和Edge浏览器不支持SSE。
-
2. 基础示例
后端(Spring Boot)
添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
创建SSE控制器:创建一个控制器来处理SSE请求,并发送事件。
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 executor = Executors.newCachedThreadPool();
@GetMapping(value = "/stream-sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamSse() {
SseEmitter emitter = new SseEmitter();
executor.execute(() -> {
try {
for (int i = 0; true; i++) {
Thread.sleep(1000); // 每秒发送一次
emitter.send(SseEmitter.event().data("SSE - " + i));
}
} catch (IOException | InterruptedException e) {
emitter.completeWithError(e);
}
});
return emitter;
}
}
前端(React)
创建SSE逻辑:在React组件中,使用Axios订阅SSE事件。
import React, { useEffect, useState } from 'react';
import axios from 'axios';
function App() {
const [messages, setMessages] = useState([]);
useEffect(() => {
const source = new EventSource('http://localhost:8080/stream-sse');
source.onmessage = (event) => {
const newMessage = event.data;
setMessages((prevMessages) => [...prevMessages, newMessage]);
};
source.onerror = (error) => {
console.error('EventSource failed:', error);
source.close();
};
return () => {
source.close();
};
}, []);
return (
<div>
<h1>SSE Messages</h1>
<ul>
{messages.map((message, index) => (
<li key={index}>{message}</li>
))}
</ul>
</div>
);
}
export default App;
工作流程
-
前端创建
EventSource
实例: 在React组件中,当组件挂载时(即在useEffect
钩子中),你会创建一个EventSource
实例,指向后端的/stream-sse
端点。
const source = new EventSource('http://localhost:8080/stream-sse');
-
自动触发后端处理器: 当
EventSource
实例被创建时,浏览器会自动向后端发送一个GET请求到/stream-sse
。这会触发你在Spring后端定义的streamSse()
方法。 -
后端发送事件: 后端的
streamSse()
方法会创建一个SseEmitter
实例,并在一个线程中不断发送事件。每当有新的数据需要发送时,后端就会通过emitter.send()
方法将数据推送到前端。 -
前端接收事件: 前端会通过
source.onmessage
事件处理器接收后端发送的消息,并更新组件的状态以显示这些消息。
注:相较于WebSocket来说,SSE更轻量级,但是只支持服务端向客户端发送消息。