[!前言]
不同于WebSockets提供了双向通信的能力,SSE只支持单向通信。但对于一些场景,如服务器向客户端发送通知或实时更新,SSE是一个简单且有效的选择。
说明
单一源事件(SSE)是一种用于实现服务器向客户端推送数据的网络技术。通常Web应用程序是基于请求-响应模式工作的,客户端需要定期向服务器发送请求以获取更新的数据。但是对于需要实时更新的应用,如聊天应用、股票市场更新等,这种轮询的方式效率不高。
SSE技术通过建立一次持久的连接,允许服务器主动向客户端发送数据,而不需要客户端发送请求。这种推送模式能够显著减少网络流量和服务器负载,同时实现实时更新。在SSE中,服务器向客户端发送一系列数据块,每个数据块以"event: "、"data: "和两个换行符开始,并以一个空行结束。客户端通过监听服务器发送的数据块来获取更新。
后端实现
以下模拟一个接口请求将每秒饭返回一条数据,持续十秒
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
| package cn.allbs.sse.controller; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 类 SSEController * * @author ChenQi * @date 2024/5/6 */@RestController public class SSEController { private final ExecutorService executorService = Executors.newSingleThreadExecutor(); @GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter receiveText(@RequestParam String question) { SseEmitter emitter = new SseEmitter(); executorService.execute(() -> { try { // 处理接收到的文本内容 String processedText = processText(question); // 将处理结果逐步发送给客户端 for (int i = 1; i <= 10; i++) { emitter.send(processedText.replace("问题", "回答") + i); Thread.sleep(1000); // 模拟每秒发送一个字符 } emitter.complete(); // 发送完毕,关闭连接 } catch (Exception e) { emitter.completeWithError(e); // 发生错误,关闭连接 } }); return emitter; } // 在实际应用中,这里可以添加对文本内容的具体处理逻辑 private String processText(String text) { return "这是问题:" + text; } }
|
前端界面可以随意一点画下即可
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
| <!DOCTYPE html> <html> <head> <title>SSE Demo</title> <meta charset="utf-8"> <script type="text/javascript"> var eventSource; function stopSSE() { if (eventSource) { eventSource.close(); } } function sendText() { var inputField = document.getElementById("input-field"); var text = inputField.value.trim(); if (text !== "") { eventSource = new EventSource("/events?question=" + text); eventSource.onmessage = function(event) { var textField = document.getElementById("result-field"); textField.value += (event.data + ", "); }; eventSource.onerror = function(event) { console.error("EventSource failed:", event); eventSource.close(); }; } } </script> </head> <body> <input type="text" id="input-field" placeholder="输入内容"> <button onclick="sendText()">发送</button><br><br> <textarea id="result-field" rows="10" cols="50" readonly></textarea><br><br> <button onclick="stopSSE()">Stop SSE</button> </body> </html>
|
访问页面
http://{ip}:{port}/index.html
实现效果
demo地址
https://github.com/chenqi92/spring-sse.git