Springboot集成SSE实现单工通信消息推送流程详解
作者:三省同学
前言
通常在一些web项目中,会涉及到想客户端推送消息,常见的有Ajax轮询、webSocket,本篇文章主要使用Springboot集成SSE实现向客户端持续推送信息。
SSE简介
服务发送事件SSE(Sever-Sent Event),就是基于 HTTP 的技术,浏览器向服务器发送一个保持长连接HTTP请求,服务器单向地向客户端以流形式持续传输数据 。这样可以节约网络资源,不需要建立新连接。
优点
服务端不需要其他的类库,开发难度较低。
不用每次建立新连接,延迟较低。 数据通过简单且广泛使用的HTTP协议而不是专有协议进行同步。
对重新建立连接和事件ID功能的内置支持。
对于利用单向通信的应用程序和服务非常有用。
缺点
客户端越多连接越多,会占用服务器大量内存和连接数。
SSE只支持UTF-8编码,不支持二进制数据。
对最大打开连接数的严格限制可能使事情变得困难,每个浏览器都设置了限制。
SSE是单向的。
Springboot集成SSE简约版
客户端发送请求到服务端,服务端以流的形式不断向客户端推送数据示例,增加帅气值。
xml依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
html代码:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Springboot集成SSE简约版</title> <script type="text/javascript"> let source = new EventSource('/get'); source.onmessage = function (event) { console.info(event.data); document.getElementById('text').innerText = event.data }; </script> </head> <body> <div id="text"></div> </body> </html>
后端代码:
@RequestMapping(value = "/get", produces = "text/event-stream;charset=UTF-8") public void push(HttpServletResponse response) { response.setContentType("text/event-stream"); response.setCharacterEncoding("utf-8"); int i = 0; while (true) { try { Thread.sleep(1000); PrintWriter pw = response.getWriter(); //注意返回数据必须以data:开头,"\n\n"结尾 pw.write("data:xdm帅气值加" + i + "\n\n"); pw.flush(); //检测异常时断开连接 if (pw.checkError()) { log.error("客户端断开连接"); return; } } catch (Exception e) { e.printStackTrace(); } i++; } }
效果:
Springboot集成SSE升级版
演示SSE的连接建立、接收数据和异常情况监听处理。
注:若浏览器不兼容在页面引入evensource.js。
<script src=/eventsource-polyfill.js></script>
客户端代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title> Springboot集成SSE升级版</title> </head> <script> let source = null; const clientId = new Date().getTime(); if (!!window.EventSource) { source = new EventSource('/sse/create?clientId=' + clientId); //建立连接 source.onopen = function (event) { setMessageInnerHTML("建立连接" + event); } //接收数据 source.onmessage = function (event) { setMessageInnerHTML(event.data); } //错误监听 source.onerror = function (event) { if (event.readyState === EventSource.CLOSED) { setMessageInnerHTML("连接关闭"); } else { console.log(event); } } } else { setMessageInnerHTML("浏览器不支持SSE"); } window.onbeforeunload = function () { close(); }; // 关闭 function close() { source.close(); const httpRequest = new XMLHttpRequest(); httpRequest.open('GET', '/sse/close/?clientId=' + clientId, true); httpRequest.send(); console.log("close"); } // 显示消息 function setMessageInnerHTML(innerHTML) { document.getElementById('text').innerHTML += innerHTML + '<br/>'; } </script> <body> <button onclick="close()">关闭连接</button> <div id="text"></div> </body> </html>
服务端代码:
private static Map<String, SseEmitter> cache = new ConcurrentHashMap<>(); String clientId; int sseId; @GetMapping("/create") public SseEmitter create(@RequestParam(name = "clientId", required = false) String clientId) { // 设置超时时间,0表示不过期。默认30000毫秒 //可以在客户端一直断网、直接关闭页面但未提醒后端的情况下,服务端在一定时间等待后自动关闭网络连接 SseEmitter sseEmitter = new SseEmitter(0L); // 是否需要给客户端推送ID if (Strings.isBlank(clientId)) { clientId = UUID.randomUUID().toString(); } this.clientId = clientId; cache.put(clientId, sseEmitter); log.info("sse连接,当前客户端:{}", clientId); return sseEmitter; } @Scheduled(cron = "0/3 * * * * ? ") public void pushMessage() { try { sseId++; SseEmitter sseEmitter = cache.get(clientId); sseEmitter.send( SseEmitter .event() .data("帅气值暴增" + sseId) .id("" + sseId) .reconnectTime(3000) ); } catch (Exception e) { log.error(e.getMessage()); sseId--; } } @GetMapping("/close") public void close(String clientId) { SseEmitter sseEmitter = cache.get(clientId); if (sseEmitter != null) { sseEmitter.complete(); cache.remove(clientId); } }
方法参数说明:
SseEmitter
.event()
.data("帅气值暴增" + sseId)
.id("" + sseId)
.reconnectTime(3000)
SseEmitter.event()
用来得到一个记录数据的容器。
.data("帅气值暴增" + sseId)
发送给客户端的数据。
.id("" + sseId)
记录发送数据的标识,服务端可以通过HttpServletRequest的请求头中拿到这个id,判断是否中间有误漏发数据。
.reconnectTime(3000)
定义在网络连接断开后,客户端向后端发起重连的时间间隔(以毫秒为单位)。
效果:
参考资料:
到此这篇关于Springboot集成SSE实现单工通信消息推送流程详解的文章就介绍到这了,更多相关Springboot消息推送内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
- Spring Boot+Vue实现Socket通知推送的完整步骤
- spring中websocket定时任务实现实时推送
- SpringBoot整合WebSocket实现后端向前端主动推送消息方式
- Spring Boot 使用 SSE 方式向前端推送数据详解
- SpringBoot+WebSocket实现消息推送功能
- Springboot整合企业微信机器人助手推送消息的实现
- SpringBoot整合WxJava开启消息推送的实现
- SpringBoot2.0集成WebSocket实现后台向前端推送信息
- SpringBoot+WebSocket+Netty实现消息推送的示例代码
- Spring SseEmitter推送消息及常用方法