背景
最近CRM系统有一个业务需求,需要将公海满足条件的线索,实时的推送到销售工作台。根据以往的经验,第一时间想到WebSocket。通过调研发现,有一种更轻量级的方式SSE,据了解,ChatGPT早起的版本也是使用的SSE技术
什么是SSE
SSE 是一种单向的、基于 HTTP 的服务器推送技术。它允许服务器通过一个长连接,单方面地向客户端推送数据流。与传统的请求-响应模式不同,SSE 建立连接后,服务器可以主动地、持续地向客户端发送更新,而客户端无需不断轮询服务器。
SSE 基于 HTTP 协议,并以文本流的方式传递数据,使用的是标准的 text/event-stream
MIME 类型。浏览器内置支持 SSE,无需额外的第三方库支持。
SSE 的工作原理
SSE 的工作流程主要包括以下几个步骤:
客户端发起连接请求: 客户端通过 JavaScript 或其他方式,向服务器发送一个 HTTP GET 请求,并在请求头中设置 Accept: text/event-stream,告知服务器客户端希望建立 SSE 连接。
服务器建立长连接并发送响应: 服务器收到请求后,会返回一个 HTTP 响应,响应头中包含:
Content-Type: text/event-stream: 指定响应内容类型为 SSE 数据流。
Cache-Control: no-cache: 禁止缓存,确保实时性。
Connection: keep-alive: 保持连接活跃。
响应体为空或包含初始数据。
服务器持续推送事件: 连接建立后,服务器可以根据需要,持续地向客户端推送事件消息。每个事件消息都是一个文本块,由 data: 行开始,后面跟着事件数据,以两个换行符 \n\n 分隔。
客户端接收和处理事件: 客户端浏览器接收到 SSE 数据流后,会自动解析事件消息,并触发 message 事件 (默认事件类型) 或自定义事件类型的事件。开发者可以通过 JavaScript 监听这些事件,并处理接收到的数据。
连接保持和重连: 连接保持活跃,直到服务器或客户端主动关闭连接。如果连接中断,浏览器会自动尝试重新连接,实现自动重连机制。
Java 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;
import java.util.concurrent.TimeUnit;
@RestController
public class SseController {
private final ExecutorService executor = Executors.newSingleThreadExecutor();
@GetMapping("/sse-spring")
public SseEmitter sseEmitter() {
SseEmitter emitter = new SseEmitter();
executor.execute(() -> {
try {
for (int i = 0; i < 10; i++) {
emitter.send("Message from Spring SSE: " + i, MediaType.TEXT_PLAIN); // 发送数据
TimeUnit.SECONDS.sleep(1);
}
emitter.complete(); // 完成 SSE 连接
} catch (IOException | InterruptedException e) {
emitter.completeWithError(e); // 处理异常并完成连接
Thread.currentThread().interrupt();
}
});
return emitter;
}
}
总结
服务器发送事件 (SSE) 是一种简单而高效的服务器推送技术,特别适用于 单向实时数据推送 的场景。相比轮询和长轮询,SSE 具有更高的效率和更好的实时性;相比 WebSocket,SSE 更轻量级,实现和维护更简单。