SpringBoot整合SSE,实现后端主动推送DEMO

前言

说起服务端主动推送,大家第一个想到的一定是WEBSOCKET 。

作为软件工程师,不能无脑使用一种技术,要结合实际情况,择优选取。

SSE(Server-Sent Events)相比于WEBSOCKET 

1、轻量化、兼容性 基于传统的HTTP协议,所以浏览器兼容性比较好

2、 只支持单向通讯。(服务器->客户端)

服务端测试代码

@RestController
public class SseController {

    private final ConcurrentHashMap<String, SseEmitter> emitters = new ConcurrentHashMap<>();

    @GetMapping("/subscribe/{id}")
    @CrossOrigin(origins = "*")
    public SseEmitter subscribe(@PathVariable String id) {
        SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
        emitters.put(id, emitter);
        emitter.onCompletion(() -> emitters.remove(id));
        emitter.onError(e -> emitters.remove(id));
        System.out.println(emitter);
        return emitter;
    }

    @GetMapping("/unbind/{id}")
    public R deleteItem(@PathVariable String id) {
        this.emitters.remove(id);
        return R.ok(true);
    }

    @GetMapping("test/send")
    public void test(){
        this.broadcastMessage("hello world");
    }


    @Async
    public void broadcastMessage(String message) {
        List<String> keysToDelete = new ArrayList<>();

        emitters.forEach((k, v) -> {
            try {
                v.send(message);
            } catch (Throwable t) {
                keysToDelete.add(k);
            }
        });
        keysToDelete.forEach(emitters::remove);
    }
}

这边是群发消息,也可以根据特定id,发送消息,发送消息可采用异步方式。

订阅消息接口需 支持跨域

设置SSE过期时间为Long的max_value

当建立连接后, 访问test/send 发送hello world

前端代码

<template>
  <div id="app">
    <div>
      {{chartStr}}
    </div>
    <div v-for="(item,index) in sseMessage" :key="index">
      {{item}}
    </div>
  </div>
</template>
<script>
  export default {
    name: 'App',
    data() {
      return {
        sseMessage: [],
        chartStr: '',
        eventSource: undefined,
      }
    },
    mounted() {
      this.getChartStr()
      this.initSSE()
    },
    beforeUnload() {
      this.unbindSSE();
    },
    methods: {
      /**
       * 初始化服务器发送事件(SSE)连接
       *
       * 此方法创建一个新的 EventSource 对象,连接到后端服务器的指定 URL,
       * 并添加一个 message 事件监听器,用于接收服务器发送的消息。
       */
      initSSE() {
        // 创建一个SSE对象,连接到后端接口
        this.eventSource = new EventSource("http://192.168.0.198:8089/subscribe/" + this.chartStr);
        // 监听message事件,接收后端发送的消息
        // this.eventSource.addEventListener("message", (event) => {
        //   //将返回data插入元素   
        //   this.sseMessage.push(event.data)
        // });
        this.eventSource.onmessage = (event) => {
          this.sseMessage.push(event.data)
        };
        this.eventSource.onerror = function (event) {
          if (event.target.readyState === EventSource.CLOSED) {
            console.log('Connection closed');
          } else {
            console.error('Error occurred', event);
          }
        }
      },

      /**
       * 取消订阅 SSE 事件源并解绑图表
       *
       * 这个方法首先检查是否存在有效的 SSE 对象。如果存在,它将关闭这个 SSE 连接。
       */
      unbindSSE() {
        if (this.eventSource) {
          this.eventSource.close();
        }
        fetch('http://192.168.0.198:8089/unbind/' + this.chartStr, {
            method: 'GET'
          })
          .catch(error => {
            console.error('Error unsubscribing:', error);
          });
      },

      /**
       * 获取唯一的图表字符串
       *
       * 此方法用于获取一个随机生成的、唯一的图表字符串。
       * 
       */
      getChartStr() {
        let array = new Uint32Array(1);
        crypto.getRandomValues(array);
        let randomHex = array[0].toString(16);
        let paddedHex = randomHex.padStart(8, '0'); // 确保32位长度
        this.chartStr = paddedHex
      },
    },
  }
</script>
<style>
  #app {
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
  }

  nav {
    padding: 30px;
  }

  nav a {
    font-weight: bold;
    color: #2c3e50;
  }

  nav a.router-link-exact-active {
    color: #42b983;
  }
</style>

测试

效果如下

拓展

EventSource

EventSource 接口提供了一个简单的 API 来接收服务器发送的事件。一旦创建了 EventSource 实例并指向一个 URL,浏览器就会尝试与服务器建立一个持久连接。

text/event-stream

text/event-stream 是一种 MIME 类型,用于描述 Server-Sent Events 的数据格式。服务器使用这种格式向客户端发送事件。每个事件由以下几部分组成:

  • data: : 必须包含的数据字段,后面跟着实际的事件数据。
  • event: : 可选的事件类型,如果指定了这个字段,onmessage 事件处理器将收到一个 event 属性,该属性包含了这个事件类型的值。
  • id: : 可选的字段,用来标识事件的序列号,客户端可以使用它来检测丢失的事件。
  • retry: : 可选的字段,表示在连接中断后重连前的延迟时间(以毫秒为单位)。

通俗解释一下

EventSource 就像是你坐在那里,服务员(服务器)主动把咖啡(信息)端到你的桌子上(浏览器)。你不需要起身询问。

text/event-stream 其实就相当于服务员的托盘,怎么个方式给你把咖啡(信息)送过来。

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值