当前位置:   article > 正文

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

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

前言

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

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

SSE(Server-Sent Events)相比于WEBSOCKET 

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

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

服务端测试代码

  1. @RestController
  2. public class SseController {
  3. private final ConcurrentHashMap<String, SseEmitter> emitters = new ConcurrentHashMap<>();
  4. @GetMapping("/subscribe/{id}")
  5. @CrossOrigin(origins = "*")
  6. public SseEmitter subscribe(@PathVariable String id) {
  7. SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
  8. emitters.put(id, emitter);
  9. emitter.onCompletion(() -> emitters.remove(id));
  10. emitter.onError(e -> emitters.remove(id));
  11. System.out.println(emitter);
  12. return emitter;
  13. }
  14. @GetMapping("/unbind/{id}")
  15. public R deleteItem(@PathVariable String id) {
  16. this.emitters.remove(id);
  17. return R.ok(true);
  18. }
  19. @GetMapping("test/send")
  20. public void test(){
  21. this.broadcastMessage("hello world");
  22. }
  23. @Async
  24. public void broadcastMessage(String message) {
  25. List<String> keysToDelete = new ArrayList<>();
  26. emitters.forEach((k, v) -> {
  27. try {
  28. v.send(message);
  29. } catch (Throwable t) {
  30. keysToDelete.add(k);
  31. }
  32. });
  33. keysToDelete.forEach(emitters::remove);
  34. }
  35. }

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

订阅消息接口需 支持跨域

设置SSE过期时间为Long的max_value

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

前端代码

  1. <template>
  2. <div id="app">
  3. <div>
  4. {{chartStr}}
  5. </div>
  6. <div v-for="(item,index) in sseMessage" :key="index">
  7. {{item}}
  8. </div>
  9. </div>
  10. </template>
  11. <script>
  12. export default {
  13. name: 'App',
  14. data() {
  15. return {
  16. sseMessage: [],
  17. chartStr: '',
  18. eventSource: undefined,
  19. }
  20. },
  21. mounted() {
  22. this.getChartStr()
  23. this.initSSE()
  24. },
  25. beforeUnload() {
  26. this.unbindSSE();
  27. },
  28. methods: {
  29. /**
  30. * 初始化服务器发送事件(SSE)连接
  31. *
  32. * 此方法创建一个新的 EventSource 对象,连接到后端服务器的指定 URL,
  33. * 并添加一个 message 事件监听器,用于接收服务器发送的消息。
  34. */
  35. initSSE() {
  36. // 创建一个SSE对象,连接到后端接口
  37. this.eventSource = new EventSource("http://192.168.0.198:8089/subscribe/" + this.chartStr);
  38. // 监听message事件,接收后端发送的消息
  39. // this.eventSource.addEventListener("message", (event) => {
  40. // //将返回data插入元素
  41. // this.sseMessage.push(event.data)
  42. // });
  43. this.eventSource.onmessage = (event) => {
  44. this.sseMessage.push(event.data)
  45. };
  46. this.eventSource.onerror = function (event) {
  47. if (event.target.readyState === EventSource.CLOSED) {
  48. console.log('Connection closed');
  49. } else {
  50. console.error('Error occurred', event);
  51. }
  52. }
  53. },
  54. /**
  55. * 取消订阅 SSE 事件源并解绑图表
  56. *
  57. * 这个方法首先检查是否存在有效的 SSE 对象。如果存在,它将关闭这个 SSE 连接。
  58. */
  59. unbindSSE() {
  60. if (this.eventSource) {
  61. this.eventSource.close();
  62. }
  63. fetch('http://192.168.0.198:8089/unbind/' + this.chartStr, {
  64. method: 'GET'
  65. })
  66. .catch(error => {
  67. console.error('Error unsubscribing:', error);
  68. });
  69. },
  70. /**
  71. * 获取唯一的图表字符串
  72. *
  73. * 此方法用于获取一个随机生成的、唯一的图表字符串。
  74. *
  75. */
  76. getChartStr() {
  77. let array = new Uint32Array(1);
  78. crypto.getRandomValues(array);
  79. let randomHex = array[0].toString(16);
  80. let paddedHex = randomHex.padStart(8, '0'); // 确保32位长度
  81. this.chartStr = paddedHex
  82. },
  83. },
  84. }
  85. </script>
  86. <style>
  87. #app {
  88. font-family: Avenir, Helvetica, Arial, sans-serif;
  89. -webkit-font-smoothing: antialiased;
  90. -moz-osx-font-smoothing: grayscale;
  91. text-align: center;
  92. color: #2c3e50;
  93. }
  94. nav {
  95. padding: 30px;
  96. }
  97. nav a {
  98. font-weight: bold;
  99. color: #2c3e50;
  100. }
  101. nav a.router-link-exact-active {
  102. color: #42b983;
  103. }
  104. </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 其实就相当于服务员的托盘,怎么个方式给你把咖啡(信息)送过来。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/849733
推荐阅读
相关标签
  

闽ICP备14008679号