Server-Sent Events (SSE) 的Spring boot 使用案例

880 阅读1分钟

摘要:SSE更简单的单向数据传输(相对于websocket单向传输数据更简单),本文主要介绍SSE + SpringBoot的使用方式,SSE的原理不做详细的介绍,大家对协议原理有兴趣的,请百度其具体的原理。

简介

Server-Sent Events (SSE) 是一种允许服务器主动向客户端浏览器发送数据的技术。它是基于 HTTP 协议的,允许服务器向客户端推送实时更新。通常用于只接收消息的场景,比如大屏实时更新最新的航班。

基本概念

  • 事件流:服务器发送的事件序列。
  • 重连:如果连接断开,客户端尝试重新连接服务器(浏览器会自动重连不需要代码控制)。
  • Last-Event-ID:客户端接收到的最后一个事件的ID,可以用来从服务器请求缺失的事件。

案例

pom.xml

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>
    </dependencies>

SseController入口

@Slf4j
@RestController
@RequestMapping(value = "sse")
public class SseController {

    private final CopyOnWriteArrayList<SseEmitter> emitters = new CopyOnWriteArrayList<>();

    @GetMapping("/events")
    public SseEmitter handleSse() {
        SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
        emitters.add(emitter);
        emitter.onTimeout(() -> emitters.remove(emitter));
        emitter.onCompletion(() -> emitters.remove(emitter));
        return emitter;
    }

    @Scheduled(fixedDelay = 1000)
    public void sendMessage(){
        String message = JSON.toJSONString(ResponseMessage.success("当前时间:" + LocalDateTime.now()));
        SseEmitter.SseEventBuilder eventBuilder = SseEmitter.event().id(System.currentTimeMillis() + "").data(message);
        emitters.forEach(emitter -> {
            try{
                emitter.send(eventBuilder);
            }catch (Exception ex){
                log.error("发送异常", ex);
            }
        });
    }

}

sse.html

前端测试入口

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>sse</title>
</head>
<body>
<div id="data"></div>

<script>
        var source = new EventSource('/sse/events');
        source.onmessage = function(event) {
            document.getElementById('data').innerHTML += event.data + '<br>';
        };
    </script>
</body>

</html>

结果

访问 http://localhost:8080/sse.html

image.png