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

  • ppt如何更换全部背景模板(PPT如何更换全部字体颜色)

    ppt如何更换全部背景模板(PPT如何更换全部字体颜色)

  • 华为手机耳机没声音怎么办(华为手机耳机没有声音是怎么回事)

    华为手机耳机没声音怎么办(华为手机耳机没有声音是怎么回事)

  • 淘宝流量是什么意思啊(淘宝的流量是什么意思?)

    淘宝流量是什么意思啊(淘宝的流量是什么意思?)

  • 剪映能剪辑多长时间的视频(剪映可以剪辑多长时间)

    剪映能剪辑多长时间的视频(剪映可以剪辑多长时间)

  • 出现解除关系加为好友(解除 关系)

    出现解除关系加为好友(解除 关系)

  • 以()为核心组成的微型计算机属于集成电路计算机(以什么为核心 以什么为目的)

    以()为核心组成的微型计算机属于集成电路计算机(以什么为核心 以什么为目的)

  • qq里面的精选照片怎么不让别人看到(qq里面的精选照片在哪里设置)

    qq里面的精选照片怎么不让别人看到(qq里面的精选照片在哪里设置)

  • 苹果放大器照片在哪里(苹果放大器照片怎么导出)

    苹果放大器照片在哪里(苹果放大器照片怎么导出)

  • 我国手机号为什么是11位数(为什么我国的手机号都是11位?)

    我国手机号为什么是11位数(为什么我国的手机号都是11位?)

  • 苹果手机升级了还能返回原版本吗(苹果手机升级了发烫怎么办)

    苹果手机升级了还能返回原版本吗(苹果手机升级了发烫怎么办)

  • shot on mi8什么手机(shot on mi 8 ud ai dual camera)

    shot on mi8什么手机(shot on mi 8 ud ai dual camera)

  • 华为手机nova7pro上市了吗(华为手机nova7pro换屏需要多少钱)

    华为手机nova7pro上市了吗(华为手机nova7pro换屏需要多少钱)

  • 魅族手机耗电快怎么解决(魅族手机耗电快充电慢怎么办)

    魅族手机耗电快怎么解决(魅族手机耗电快充电慢怎么办)

  • 抖音直播封禁是封永久吗(抖音直播封禁是管理发价钱微信)

    抖音直播封禁是封永久吗(抖音直播封禁是管理发价钱微信)

  • 前程无忧申请的可以撤回吗(前程无忧申请的简历可以修改吗)

    前程无忧申请的可以撤回吗(前程无忧申请的简历可以修改吗)

  • 手机用充电宝充电有什么影响吗(手机用充电宝充电发烫)

    手机用充电宝充电有什么影响吗(手机用充电宝充电发烫)

  • 苹果x隐藏相册怎么找出来(苹果x隐藏相册可以设密码吗)

    苹果x隐藏相册怎么找出来(苹果x隐藏相册可以设密码吗)

  • 华为荣耀20怎么插耳机(华为荣耀20怎么刷机)

    华为荣耀20怎么插耳机(华为荣耀20怎么刷机)

  • oppok3上市时间(oppoK3上市时间)

    oppok3上市时间(oppoK3上市时间)

  • 怎么开通直播(小红书怎么开通直播)

    怎么开通直播(小红书怎么开通直播)

  • 怎么查找手机删除的软件(怎么查找手机删除的信息内容)

    怎么查找手机删除的软件(怎么查找手机删除的信息内容)

  • 微信亲属卡解绑对方知道吗(微信亲属卡解绑了怎么看消费记录)

    微信亲属卡解绑对方知道吗(微信亲属卡解绑了怎么看消费记录)

  • qq勋章墙在哪(新版qq勋章墙在哪)

    qq勋章墙在哪(新版qq勋章墙在哪)

  • ReactOS怎么安装?Hyper-V虚拟机安装ReactOS详细图文教程(如何安装react)

    ReactOS怎么安装?Hyper-V虚拟机安装ReactOS详细图文教程(如何安装react)

  • pqv2isvc.exe - pqv2isvc是什么进程 有什么作用

    pqv2isvc.exe - pqv2isvc是什么进程 有什么作用

  • 私立学校要交社保吗
  • 旅游业成本具体有哪些
  • 零申报还要抄税吗
  • 个人开具发票需要税号吗
  • 资本公积只能转现金吗
  • 银行承兑贴现的会计分录怎么做
  • 会计工作的基本认识
  • 工程资金占用计算利率是多少
  • 所得税汇算清缴时间期限
  • 应收账款贷方余额怎么处理
  • 个人所得税申报方式选哪个
  • 工程公司安装中央空调能按混合销售计算增值税么?
  • 无票收入如何做账
  • 2020水利基金
  • 个人生产经营所得
  • 税控盘减免在哪里填报
  • 养牛需要活动场地吗
  • 行政事业单位国有资产处置收入包括
  • 支付宝对公账户还款清零要多久
  • 免抵退税额抵减额怎么理解
  • 进行财产清查
  • 小规模纳税人 核定
  • 加权平均数是什么意思的权
  • 申报个税按计提工资还是实际发放
  • 采购开票税率
  • 个税手续费返还政策文件
  • 一般纳税人车辆过户给个人开票几个点
  • 企业重组后的债务怎么算
  • 纳税人如何申请延期缴纳税款
  • linux系统备份整个硬盘的命令
  • 怎么提升电脑速度
  • 无形资产的摊销年限不得低于多少年
  • 柏林亚历山大广场1980
  • 增值税加计抵减怎么算
  • 工业企业制造费用占比
  • 公司注册认缴的期限一般是多少
  • unity ik
  • 会计制度备案附件要上传什么
  • 只有进项税没有销项税如何报税
  • 进项不认证有什么风险
  • 其他应收账款怎么做预算会计分录
  • 企业之间的借款利息收入缴纳增值税吗?
  • python中的thread
  • 已缴款未入库是缴费成功了吗
  • 销售折扣单独开票的会计分录
  • 汇算清缴费用调整怎么做账
  • 税务已注销工商如何注销
  • sql server 2008 怎么使用
  • 代购进口货物垫付方案
  • 企业支付的一次性就业补助金
  • 投资房地产的后续计量有哪几种模式
  • 免费赠送客户入群的文案
  • 运费少给怎么办
  • 工程预付款入账
  • 融资租赁中承租人的义务
  • 当月发票已认证还能作废吗
  • 老办法退休金如何计算
  • mysql安装配置教程5.7.26
  • 手把手教你安装实木门
  • win10预览版21301bug
  • 如何解决叛逆心理
  • windows7禁止开机启动
  • 没有启动界面
  • win7怎么看磁盘
  • linux系统评测
  • 高通ar芯片
  • prototype.js中文文档
  • python true的用法
  • bat 远程连接
  • vuex的理解
  • shell脚本监控进程
  • js正则匹配数字
  • 悬浮工具栏
  • 外经证的有效期是多久
  • 税务评估风险等级是什么
  • 租房减免税收
  • 多交了个人所得税怎么算
  • 国家税务总局72号文件
  • 如何做好税务党建工作
  • 上海买新房办贷款流程
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设