SSE(Server Sent Event):服务器发送事件,客户端发起请求后,连接会一直保持,等待服务器发送数据,它与 WebSocket 的明显区别就是 SSE 是半双工的,只能服务端向客户端发送数据,优点是不需要其他的类库,开发难度较低,默认支持断线重连

1. 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. Controller

@CrossOrigin
@RestController
public class SSEController{

    private static final Map<Integer, SseEmitter> sseCache = new ConcurrentHashMap<>();

    @GetMapping("/subscribe")
    public SseEmitter subscribe(Integer userId) {
        SseEmitter sseEmitter = new SseEmitter(5 * 60 * 1000L);
        sseCache.put(userId, sseEmitter);
        sseEmitter.onTimeout(() -> sseCache.remove(userId));
        sseEmitter.onCompletion(() -> System.out.println("完成"));
        return sseEmitter;
    }

    @GetMapping("/send")
    public void send(Integer userId, String msg) throws IOException {
        SseEmitter sseEmitter = sseCache.get(userId);
        if (sseEmitter != null) {
            sseEmitter.send(msg);
        }
    }

    @GetMapping("/over")
    public void over(Integer userId) {
        SseEmitter sseEmitter = sseCache.get(userId);
        if (sseEmitter != null) {
            sseEmitter.complete();
            sseCache.remove(userId);
        }
    }
}

3. html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>sse测试</title>
    <script>
        const source = new EventSource('http://localhost:8080/subscribe?userId=1');
        source.onmessage = function (event) {
            let log = document.getElementById('log');
            log.innerHTML = "onMessage:" + event.data + "<br>" + log.innerHTML;
        };
        source.onopen = function (event) {
            console.log(event);
            let log = document.getElementById('log');
            log.innerHTML = "开启回调";
        };
    </script>
</head>
<body>
<div id="log"></div>
</body>
</html>

4. 测试

image.png

Q.E.D.


盛年不重来,一日难再晨。