位置: IT常识 - 正文

SSE:后端向前端发送消息(springboot SseEmitter)(sse后端向前端推送 前端只能收到 末尾的值)

编辑:rootadmin
SSE:后端向前端发送消息(springboot SseEmitter) 背景

推荐整理分享SSE:后端向前端发送消息(springboot SseEmitter)(sse后端向前端推送 前端只能收到 末尾的值),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:后端向前端返回数据,后端给前端的接口是什么,ssm前端到后端参数传递,ssm前端到后端参数传递,后端给前端的接口是什么,后端向前端传值的两种方法,sse后端向前端推送 前端只能收到 末尾的值,后端向前端传值的两种方法,内容如对您有帮助,希望把文章链接给更多的朋友!

有一个项目,前端vue,后端springboot。现在需要做一个功能:用户在使用系统的时候,管理员发布公告,则使用系统的用户可以看到该公告。 基于此,一个简单的方案:前端使用JS方法setInterval,重复调用后端公告获取接口。此方法有几点缺陷:

循环调用的时间间隔不好确定:太长了,获取公告的时效有延迟;太短了,给服务器造成压力,很多请求都是无用的(公告发布的时间不定,很可能几天都没有新公告);token的续期问题:项目中,前端请求,需要带上token,token有过期时间,如果用户一直使用(前后端有交互),会无感续期。如果有这种定时循环和后端交互的场景,就会造成token用不过期(循环的调用会触发续期),当然,可以在续期中,排除某个场景的请求,但是这样的设计不好,因为这种场景太多了,就会造成维护上的困难。

因此就想到了,如果后端主动向前端推送消息,这个问题就可以完美解决。

方案

有两种方案可以实现后端向前端推送消息:

使用websocket;使用sse;

这里介绍SSE的方式(如果系统中对这种消息的准确性和可靠性有严格的要求,则使用websocket,websocket的使用相对复杂的多); 如果想了解SSE的详细基础知识,可以参考阮一峰老师的这篇文章:Server-Sent Events 教程

SSE后端代码SSE:后端向前端发送消息(springboot SseEmitter)(sse后端向前端推送 前端只能收到 末尾的值)

SpringMVC中,已经集成了该功能,所以无需额外引入jar包,直接上代码:

@RestController@RequestMapping("/notice")public class NoticeController { @Autowired private NoticeService noticeService; @GetMapping(path = "createSseEmitter") public SseEmitter createSseEmitter(String id) { return noticeService.createSseEmitter(id); } @PostMapping(path = "sendMsg") public boolean sendMsg(String id, String content) { noticeService.sendMsg(id, content); return true; }}@Slf4j@Servicepublic class NoticeServiceImpl implements NoticeService { @Autowired @Qualifier("sseEmitterCacheService") private CacheService<SseEmitter> sseEmitterCacheService; @Override public SseEmitter createSseEmitter(String clientId) { if (StringUtil.isBlank(clientId)) { clientId = UUID.randomUUID().toString().replace("-", ""); } SseEmitter sseEmitter = sseEmitterCacheService.getCache(clientId); log.info("获取SSE,id={}", clientId); final String id = clientId; sseEmitter.onCompletion(() -> { log.info("SSE已完成,关闭连接 id={}", id); sseEmitterCacheService.deleteCache(id); }); return sseEmitter; } @Override public void sendMsg(String clientId, String content) { if (sseEmitterCacheService.hasCache(clientId)) { SseEmitter sseEmitter = sseEmitterCacheService.getCache(clientId); try { sseEmitter.send(content); } catch (IOException e) { log.error("发送消息失败:{}", e.getMessage(), e); throw new BusinessRuntimeExcepption(CustomExcetionConstant.IO_ERR, "发送消息失败", e); } } else { log.error("SSE对象不存在"); throw new BusinessRuntimeExcepption("SSE对象不存在"); } }}

这里,只列出了核心的代码,简而言之,需要做到两点即可:

前端首先是发起一个请求,创建SseEmitter,即createSseEmitter方法,该方法必须返回一个SseEmitter对象;返回的SseEmitter,后端必须要缓存起来(我用的是ehcache,也可以直接定义一个map来缓存);

为什么要这么做?看下文,后端代码一起来分析就明白了。

前端代码

由于,我请求该接口,需要带上token,所以直接使用EventSource不行,另外这个IE也不支持。所以选择了一个工具:event-source-polyfill。

先安装event-source-polyfillnpm install event-source-polyfill然后使用:import { EventSourcePolyfill } from "event-source-polyfill"; created() { let _this = this; this.source = new EventSourcePolyfill( "/" + process.env.VUE_APP_MANAGER_PRE_API_URL + "/notice/createSseEmitter?id=" + uuid(), { headers: { [process.env.VUE_APP_OAUTH_AUTHORIZATION]: store.getters.getToken, }, //重连时间间隔,单位:毫秒,默认45000毫秒,这里设置为10分钟 heartbeatTimeout: 10 * 60 * 1000, } ); this.source.onopen = () => { console.log("NOTICE建立连接"); }; this.source.onmessage = (e) => { _this.scrollMessage = e.data; console.log("NOTICE接收到消息"); }; this.source.onerror = (e) => { if (e.readyState == EventSource.CLOSED) { console.log("NOTICE连接关闭"); } else if (this.source.readyState == EventSource.CONNECTING) { console.log("NOTICE正在重连"); //重新设置header this.source.headers = { [process.env.VUE_APP_OAUTH_AUTHORIZATION]: store.getters.getToken, }; } else { console.log(e); } }; },

有几点说明:

new EventSourcePolyfill中,可以带入headerheartbeatTimeout是一个心跳时间,默认情况下间隔heartbeatTimeout后,会触发重新连接后端接口;this.source.headers,该行的作用是在重连的时候重新设置header,如果不这样,那么重连的时候,用的参数信息,还是和最开始的一样(包括本例中url中的id)。而由于我的项目中,如果token其他操作触发了刷新token,则有效token可能会变,所以,这里取缓存中放置的token,而不应该使用最初的token。 好了,这样就基本实现了我们所需要的功能了。特别注意

前端配置了代理,所以一直收不到后端发送的消息,尝试加入以下参数:

devServer: { compress:false, …………}问题

之前在写后端的时候提到了两个问题:为什么要返回SseEmitter对象?为什么要缓存SseEmitter对象? 其实看过SSE的原理,都应该明白:这就是一个长连接,前端调用创建SseEmitter对象的接口,虽然接口返回了,但是并未结束(这就是为什么要返回SseEmitter对象,如果返回的是一个其他对象,就和普通的接口没两样了, 该接口就直接结束了),请看下截图: 发起请求之后,一直是待处理,并未结束,10分钟之后,该请求被取消(前端设置的重连),然后重新发起连接,重新发起的连接也是在等待中。只有接收到消息后,这个请求的状态码才是200,但是这个时候才连接已经建立好了。其中的细节,这里不做讲述。 所以,如果再使用SseEmitter对象发送消息,则前端就可以收到对象的消息了(即实现后端向前端发送消息)。这里使用的SseEmitter对象,就是createSseEmitter接口返回的对象(也就是使用哪个SseEmitter对象,就可以向哪个前端发送消息)。这也就是为什么要缓存SseEmitter对象的原因了。

效果

通过调用发送消息接口,前端即可立即展示发送的消息:

本文链接地址:https://www.jiuchutong.com/zhishi/311892.html 转载请保留说明!

上一篇:帝国CMS如何以原文件名命名附件(帝国cms怎么用)

下一篇:uni-app组件-应用简单快速上线(uniapp组件使用)

  • 快手头像挂件怎么取消(快手头像挂件怎么设置)

    快手头像挂件怎么取消(快手头像挂件怎么设置)

  • 移动充值卡不能充支付宝了(移动充值卡不能用)

    移动充值卡不能充支付宝了(移动充值卡不能用)

  • hd7700相当于n卡哪个(hd7700series相当于)

    hd7700相当于n卡哪个(hd7700series相当于)

  • vivoy95定制版什么意思(vivox9定制版)

    vivoy95定制版什么意思(vivox9定制版)

  • 可以慢放视频的软件(可以慢放视频的免费手机软件)

    可以慢放视频的软件(可以慢放视频的免费手机软件)

  • 公网ip光猫必须桥接吗(申请到公网ip后,光猫要怎么弄)

    公网ip光猫必须桥接吗(申请到公网ip后,光猫要怎么弄)

  • 闲鱼售出不退不换合法吗(闲鱼售出不退不换是真的吗)

    闲鱼售出不退不换合法吗(闲鱼售出不退不换是真的吗)

  • 苹果手机包装盒上有序列号吗(苹果手机包装盒序列号怎么看)

    苹果手机包装盒上有序列号吗(苹果手机包装盒序列号怎么看)

  • 屏幕赫兹什么意思(手机屏幕赫兹有什么区别)

    屏幕赫兹什么意思(手机屏幕赫兹有什么区别)

  • oppo充电提示音能关掉吗(oppo充电提示音教程)

    oppo充电提示音能关掉吗(oppo充电提示音教程)

  • 拼多多成立时间(拼多多成立时间是哪一年)

    拼多多成立时间(拼多多成立时间是哪一年)

  • 一张身份证可以注册几个微信号(一张身份证可以买两张火车票吗)

    一张身份证可以注册几个微信号(一张身份证可以买两张火车票吗)

  • 华为bah-w09是什么型号(华为bah2-w09参数)

    华为bah-w09是什么型号(华为bah2-w09参数)

  • ja是什么版本(苹果手机型号ja是什么版本)

    ja是什么版本(苹果手机型号ja是什么版本)

  • tbus文件能删除吗(tbus_888可以删除吗)

    tbus文件能删除吗(tbus_888可以删除吗)

  • 华为手机克隆后旧手机数据会消失吗(华为手机克隆后新手机数据会消失吗)

    华为手机克隆后旧手机数据会消失吗(华为手机克隆后新手机数据会消失吗)

  • 背景在什么选项卡(背景格式在哪个选项中)

    背景在什么选项卡(背景格式在哪个选项中)

  • 华为mate30清除后台程序(华为mate30pro清除数据还能找回手机吗)

    华为mate30清除后台程序(华为mate30pro清除数据还能找回手机吗)

  • 淘宝漏发不承认怎么办(淘宝漏发不处理怎么办)

    淘宝漏发不承认怎么办(淘宝漏发不处理怎么办)

  • 小米智能锁sn码在哪里(小米智能锁sn码怎么查)

    小米智能锁sn码在哪里(小米智能锁sn码怎么查)

  • mp3播放器从哪里下载音乐(mp3里的播放模式在哪里)

    mp3播放器从哪里下载音乐(mp3里的播放模式在哪里)

  • 充电头17位序列号意义(充电头17位序列代表什么)

    充电头17位序列号意义(充电头17位序列代表什么)

  • 火狐浏览器&谷歌浏览器&Edge浏览器修改默认UA(User-Agent)(火狐浏览器下载安装)

    火狐浏览器&谷歌浏览器&Edge浏览器修改默认UA(User-Agent)(火狐浏览器下载安装)

  • 腾讯手游助手如何取消开机自动启动?(腾讯手游助手如何隐藏键位)

    腾讯手游助手如何取消开机自动启动?(腾讯手游助手如何隐藏键位)

  • 纳税人返税是什么意思
  • 兴业银行汇款手续费
  • 企业分红缴纳所得税
  • 财务报表审计的标准
  • 小规模附加税减半吗
  • 车辆租赁发票税点
  • 小微企业免税收入有哪些
  • 公司注销后专利还能转让吗
  • 工程结算账务处理实例
  • 短期借款会计核算
  • 小规模纳税人标准2019
  • 小规模纳税人每个月需要报什么税
  • 公司未开展业务就没有债权债务吗
  • 未计提坏账准备金额在哪个科目
  • 矿泉水售卖方式
  • 替票和代票的区别是什么
  • 房地产停车场属于公共配套设施吗
  • 工业厂房的辅助用房
  • 客户扣款会计分录明细科目
  • 电子承兑转出后多久到账
  • 会计分录如何试算出来的
  • 预付账款是企业销售过程中形成的一种非货币形式的债权
  • win10声音设置面板在哪
  • 不动产增值税怎么算
  • 待抵扣进项税额什么意思
  • 年中建账年初余额怎么录入
  • 预付装修费的会计处理分录
  • 开源cti
  • js中...的用法
  • ai作画
  • nodejs 2020
  • sftp 加密算法
  • win+e快捷键在哪
  • 清算汇缴报表填什么内容
  • 增值税发票已认证抵扣还可以进项税额转出吗
  • 羊羊 过好
  • 增值税专用发票和普通发票的区别
  • 收缴违约金
  • 公司注销剩余的发票怎么作废
  • 销售货物未收到货款的会计分录怎么写
  • 查询不到shsh怎么回事
  • 完税证明可以去税务局补打吗
  • mysql 管理员登录
  • mysql数据库的设计与实现
  • mongodb查询操作
  • 房租收入如何纳税
  • 建筑施工仪器设备有哪些
  • 固定资产一次性计入费用的账务处理
  • 投资收益记账
  • 顺流交易为什么也要减
  • 固定资产的折余价值和账面价值如何确定
  • 转增股股价
  • 在外地设办事处需要办什么手续
  • 工会会费收入计入会计科目
  • 应付账款账户怎么结转
  • 汇兑损益的税务处理
  • 福利设施的定义
  • 工程物资盘盈为什么冲减在建工程
  • sql语句编译执行过程
  • mysql索引方式有哪些
  • freebsd常用命令
  • Windows XP/Vista/Windows 7常见蓝屏故障分析
  • mac怎样解压缩
  • 苹果macOS 14 正式发布
  • 怎么把u盘两个盘合并到一起
  • gho文件硬盘安装
  • win10 version 1607 累积更新失败卡了怎么办
  • ubuntu必备软件10款
  • win10rs2是哪个版本
  • linux中压缩文件
  • win7打开tftp服务器
  • 显示演示模式
  • 三种方法完美解决问题
  • 如何解决win7系统转为xp系统出现蓝屏怎么办啊
  • windows 10 升级
  • computed缓存
  • vue assign
  • python中的\r
  • 广西电子税务局电话人工客服电话
  • 建筑劳务分包业务范围
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设