Springboot -- Server-send Event(SSE)服务推送事件

什么是SSE

       Server-Sent Event 网页可以获取由服务器主动推送的数据。

SSE的作用

       从他的解释中可以看出,SSE可以实现由服务器主动向前端推送数据,因此可以实现某些需要持续获取数据的情形。
       比如在文件上传时,一些较大的文件可能上传缓慢,我们不可能让客户一直等待至上传结束才知道上传结果,这样对用户的体验是恐怖的,更是不合理的。我们需要让用户了解实时的上传进度,并在上传过程中出现异常时可以及时报错。
在这里插入图片描述       或许我们可以为本次上传任务记录唯一的任务ID,并将任务另起线程执行,计算本次任务的上传进度、获取任务之行的状态等信息,存入缓存。提供一个可以根据任务ID查询任务进度和状态的接口,并通知前端轮询查询任务进度。
       上面的方法,需要前端不断轮询并创建HTTP链接,而且一般还需要介入第三方数据库,如Redis来存储我们的任务信息,实现起来也比较麻烦。但是通过SSE我们可以很简单的来实现由服务端推送的实时数据。

SSE的优点

SSE部署在 HTTP协议之上,现有的服务器软件都支持。
SSE是一个轻量级协议,相对简单。
SSE默认支持断线重连。

简单示例代码

服务端

  • 服务端必须标注前端需要准备接受text/event-stream类型的数据,produces = MediaType.TEXT_EVENT_STREAM_VALUE
  • 服务端在最后返回一个stop事件,用作前端判断事件结束
    @GetMapping(value = "streamtest/{length}",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<Object>> streamtest(@PathVariable("length") int length){
    
    

			//返回一个流 根据传入的长度n,我们每间隔一秒返回n条信息
			//事件名称默认都是message,最后添加一个stop事件
        Flux result = Flux.fromStream(IntStream.rangeClosed(1,length+1).boxed().map(
                i->{
    
    
                    try {
    
    
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
    
    
                    }
                    if(i>length)
                        //最后增加一个事件信息 用来通知前端不要再重复请求后台了
                        return ServerSentEvent.<Object>builder()
                                .event("stop") //和前端addEventListener监听的事件一一对应
                                .data(-1)//ServerSentEvent必须要传data,否在前台接受不到
                                .build();
                    else
                        return String.format("测试数据%d",i);
                }
        ));

        return result;
    }

客户端

  • 前端在接受完服务端的数据后,会自动重连再次请求服务,因此我们需要手动关闭
//判断浏览器是不是支持SSE
if (window.EventSource) {
    
    
  // 创建 EventSource 对象连接服务器
  const source = new EventSource('http://localhost:8090/server/test/streamtest/3');

  // 连接成功窒触发open事件
  source.addEventListener('open', () => {
    
    
    console.log('Connected');
  }, false);

  // 服务器发送信息到客户端时,如果没有 event 字段,默认会触发 message 事件
  source.addEventListener('message', e => {
    
    
    console.log(`data: ${
      
      e.data}`);
  }, false);

  // 自定义 EventHandler,在收到 event 字段为 stop 的消息时触发
  //在这里我们将SSE关闭
  source.addEventListener('stop', e => {
    
    
    source.closed();
    console.log('Closed'); 
  }, false);

  // 连接异常时会触发 error 事件并自动重连
  source.addEventListener('error', e => {
    
    
    if (e.target.readyState === EventSource.CLOSED) {
    
    
      console.log('Disconnected');
    } else if (e.target.readyState === EventSource.CONNECTING) {
    
    
      console.log('Connecting...');
    }
  }, false);
} else {
    
    
  console.error('Your browser doesn\'t support SSE');
}

结果

>Connected
>data: 测试数据1
>data: 测试数据2
>data: 测试数据3
>Closed

猜你喜欢

转载自blog.csdn.net/qq_40096897/article/details/121394810
今日推荐