位置: 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组件使用)

  • 荣耀x10的分辨率是多少(荣耀x10屏幕分辨率)

    荣耀x10的分辨率是多少(荣耀x10屏幕分辨率)

  • 华为锁屏怎么延长(华为锁屏延长)

    华为锁屏怎么延长(华为锁屏延长)

  • 万用表com接红还是黑(万用表com接什么)

    万用表com接红还是黑(万用表com接什么)

  • 华为p20升级emui10会变卡么(华为p20升级鸿蒙2.0)

    华为p20升级emui10会变卡么(华为p20升级鸿蒙2.0)

  • 拼多多里待支付是什么情况(拼多多里待支付是什么意思)

    拼多多里待支付是什么情况(拼多多里待支付是什么意思)

  • excel数字变成井号怎么办(excel数字变成井号键)

    excel数字变成井号怎么办(excel数字变成井号键)

  • 微信视频超过5分钟怎么发送(微信视频超过5分钟怎么撒回)

    微信视频超过5分钟怎么发送(微信视频超过5分钟怎么撒回)

  • 华为mate 30啥时候上市(华为明天mate30)

    华为mate 30啥时候上市(华为明天mate30)

  • 如何设置指纹开屏幕(如何设置指纹开手机)

    如何设置指纹开屏幕(如何设置指纹开手机)

  • sim卡注册失败怎么处理(sim卡注册失效)

    sim卡注册失败怎么处理(sim卡注册失效)

  • 固态硬盘快在哪里(固态硬盘怎么才能更快)

    固态硬盘快在哪里(固态硬盘怎么才能更快)

  • 怎么把qq背景弄成空白(怎么把QQ背景弄成空白)

    怎么把qq背景弄成空白(怎么把QQ背景弄成空白)

  • 苹果突然重启是为什么(苹果突然重启是什么原因)

    苹果突然重启是为什么(苹果突然重启是什么原因)

  • 华为mate20pro解锁方式(华为mate20pro解锁账户锁)

    华为mate20pro解锁方式(华为mate20pro解锁账户锁)

  • 复印机和打印机的区别(复印机和打印机是一种吗)

    复印机和打印机的区别(复印机和打印机是一种吗)

  • 镜头分为哪几种(拍摄镜头分为哪几种)

    镜头分为哪几种(拍摄镜头分为哪几种)

  • 淘宝怎样设置个人年龄(淘宝怎么设置个人资料)

    淘宝怎样设置个人年龄(淘宝怎么设置个人资料)

  • qq音乐怎么在电脑上退出啊(QQ音乐怎么在电视上播放)

    qq音乐怎么在电脑上退出啊(QQ音乐怎么在电视上播放)

  • mde6是小米几(小米mde6s图片及价格)

    mde6是小米几(小米mde6s图片及价格)

  • word上标怎么弄(word中的上标怎么弄)

    word上标怎么弄(word中的上标怎么弄)

  • ios13闪光灯怎么开(苹果13系统闪光灯)

    ios13闪光灯怎么开(苹果13系统闪光灯)

  • xr原彩显示要不要开(xr 原彩显示)

    xr原彩显示要不要开(xr 原彩显示)

  • 进快手直播间怎么隐身(进快手直播间怎么隐藏自己)

    进快手直播间怎么隐身(进快手直播间怎么隐藏自己)

  • 华为Nova2s电池容量是多少(华为nova2s电池容量在哪里看)

    华为Nova2s电池容量是多少(华为nova2s电池容量在哪里看)

  • 苹果手机4g变3g怎么办(苹果手机4G变3G没有信号差)

    苹果手机4g变3g怎么办(苹果手机4G变3G没有信号差)

  • 什么是隔空播放2(什么是隔空播放代码)

    什么是隔空播放2(什么是隔空播放代码)

  • 怎样才能防止IP号泄露?(怎样才能防止臭虫在卧室里呢)

    怎样才能防止IP号泄露?(怎样才能防止臭虫在卧室里呢)

  • win10电脑记事本在哪(win10电脑记事本打不开显示错误)

    win10电脑记事本在哪(win10电脑记事本打不开显示错误)

  • PHPCMS 都能干什么?(phpcms怎么样)

    PHPCMS 都能干什么?(phpcms怎么样)

  • 申请A级纳税企业需具备哪些条件
  • 期末有留底税额可需要进行账务处理
  • 汇算清缴计提所得税在哪个月
  • 税金及附加属于管理费用吗
  • 进项税额转出期限是多少
  • 税盘维护费抵扣
  • 收到货款发货了没开发票怎么入账
  • 利息收入记借方负数表示增加还是减少
  • 应纳税所得额为什么要减去60000
  • 外汇结汇成人民币违法吗
  • 电子税务局中在哪看本月开票统计表
  • 特种设备电梯如何监管
  • 欠缴税款的后果
  • 预提佣金会计分录是什么
  • 发票存在哪些税务风险?
  • 汽车租赁用不用交税
  • 进口增值税已付发票未到如何入账
  • 应付职工薪酬科目有余额怎么调整
  • 固定资产入账价值包括
  • 零售产品的进项税怎么算
  • 广告公司需要交消费税吗
  • 基建项目税率
  • 个体餐饮店交税吗
  • 1697509557
  • 公司客户招待费用标准
  • linux 中cat
  • php serialize
  • env文件夹是什么文件
  • 微软输入法卸载不了
  • 斯科默岛白玉草丛中的海鹦,威尔士彭布罗克郡 (© Ross Hoddinott/Minden Pictures)
  • iis防盗链
  • 持有至到期投资在资产负债表怎么填
  • 劳务公司成本票不够怎么办
  • 保险公司的应收账款有哪些
  • 购买方如何开具红字发票给销售方
  • 增值税发票完税证明图片
  • 企业从政府取得的非货币资产应该按照什么计量
  • 预提财务费用
  • mongodb基本操作命令
  • 投资性房地产由成本模式转为公允价值模式
  • 政府扶持资金所得税税率
  • 本月购进原材料取得增值税专用发票
  • 政府补助确认递延所得税负债
  • 城建税50%减免条件
  • 车辆保险费会计账务处理
  • 个人购买股权和公司购买股权比较
  • 企业发生装修费就计入长期待摊费用吗还是
  • 预包装食品是否可以称重销售吗
  • 母公司以房产投资子公司
  • 原材料入库单应根据采购订单还是到货数量
  • 账簿的类型有哪几种
  • sqlserver2000数据库迁移到2008r2
  • solaris 安装
  • 在windows操作中
  • 怎么在bios中开启cs1
  • cmos开机密码的清除的二种方法
  • 如何创建一个wifi
  • linux文本处理实验报告
  • steam怎么sl
  • Linux httpd(apache)启动失败 解决办法
  • win7英语
  • win1020th2
  • win7系统c盘占用空间大
  • win7系统无线网络
  • win10安装驱动器
  • 冒充咋写
  • cocos2d-js-min.js
  • TNet Tasharen Networking 学习总结
  • jquery上下移动
  • js-cookie vue
  • js原型使用场景
  • unity投影交互开发
  • python27文件夹
  • 增值税预缴税款在主表怎么填写
  • 云南省电子税务
  • 无锡第三税务分局
  • 北京地税局报税时间
  • 中国税务报订阅电话
  • 中国税务报客户端
  • 办理企业步骤
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设