[!前言]
不同于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
image.png

实现效果

recording.gif

demo地址

https://github.com/chenqi92/spring-sse.git