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

  • 淘宝“每日新品”展示规则说明(il淘宝)

    淘宝“每日新品”展示规则说明(il淘宝)

  • html转义字符(html %转义)

    html转义字符(html %转义)

  • 荣耀x10max机身尺寸是多少(荣耀x10max机身尺寸)

    荣耀x10max机身尺寸是多少(荣耀x10max机身尺寸)

  • 苹果删除的软件如何恢复(怎么找回苹果删除的软件)

    苹果删除的软件如何恢复(怎么找回苹果删除的软件)

  • 为什么都没有耳机孔了(为什么有些人耳朵没有耳垂)

    为什么都没有耳机孔了(为什么有些人耳朵没有耳垂)

  • 学信网密码和密保问题都忘记了怎么办(学信网密码和密码是什么)

    学信网密码和密保问题都忘记了怎么办(学信网密码和密码是什么)

  • qq扩列错过加好友怎么办(qq扩列的人不小心删了怎么办)

    qq扩列错过加好友怎么办(qq扩列的人不小心删了怎么办)

  • 微信分享链接无法打开(微信分享链接打不开怎么办)

    微信分享链接无法打开(微信分享链接打不开怎么办)

  • 钉钉班级群怎么解散(钉钉班级群怎么给孩子请假)

    钉钉班级群怎么解散(钉钉班级群怎么给孩子请假)

  • 苹果11接电话没声音(苹果11接电话没声音按免提才能听的到)

    苹果11接电话没声音(苹果11接电话没声音按免提才能听的到)

  • win10我的电脑怎么调出来(win10我的电脑)

    win10我的电脑怎么调出来(win10我的电脑)

  • 电脑带bar是什么意思(电脑中bar是什么意思)

    电脑带bar是什么意思(电脑中bar是什么意思)

  • 电话手表没卡能用吗(小天才电话手表怎么插卡)

    电话手表没卡能用吗(小天才电话手表怎么插卡)

  • 怎么知道支付宝好友把我拉黑或删除(怎么知道支付宝对方有没有删除自己)

    怎么知道支付宝好友把我拉黑或删除(怎么知道支付宝对方有没有删除自己)

  • 路由表中包含哪些信息(路由表中包含哪一项信息)

    路由表中包含哪些信息(路由表中包含哪一项信息)

  • ipad在哪里保修(ipad保修计划怎么用)

    ipad在哪里保修(ipad保修计划怎么用)

  • 手机微信怎么升级版本(手机微信怎么升级苹果)

    手机微信怎么升级版本(手机微信怎么升级苹果)

  • 手机充电器1a和2a的区别(手机充电器1A和2A的区别)

    手机充电器1a和2a的区别(手机充电器1A和2A的区别)

  • 快手连麦教程(快手连麦教程图片)

    快手连麦教程(快手连麦教程图片)

  • 手机每天ip地址一样吗(每个手机ip地址)

    手机每天ip地址一样吗(每个手机ip地址)

  • 华为P30如何输入各种特殊符号(华为p30输入法怎么设置)

    华为P30如何输入各种特殊符号(华为p30输入法怎么设置)

  • 抖音首发怎么创作(抖音首发怎么创作视频)

    抖音首发怎么创作(抖音首发怎么创作视频)

  • 微信聊天静音如何取消(微信聊天静音怎么恢复声音)

    微信聊天静音如何取消(微信聊天静音怎么恢复声音)

  • 三星g9650ds是国行吗(三星g965f是哪国的)

    三星g9650ds是国行吗(三星g965f是哪国的)

  • 万用表有哪些档位(万用表有哪些档位和插孔)

    万用表有哪些档位(万用表有哪些档位和插孔)

  • wps格式刷快捷键(wps格式刷快捷键用不了怎么办)

    wps格式刷快捷键(wps格式刷快捷键用不了怎么办)

  • 印花税办理流程
  • 劳务分包人是实际施工人吗
  • 增值税纳税申报时间
  • 公司账户进账必须交税吗
  • etc发票开票中
  • etc怎么取过路费啊
  • 加计扣除企业所得税季报申报
  • 营改增后自建厂房抵扣
  • 公司改变工资结构变相降工资怎么办
  • 房屋所有权变更登记证书
  • 纳税营业额包含免税营业额吗?
  • 审核费用发票需要发票吗
  • 获赠或继承来的房屋以后再转让
  • 处置固定资产按残值还是净值
  • 资产处置收益的含义
  • 业务招待费进项税额转出
  • 员工饭卡充值是哪个部门做
  • 劳务所得个税税率表
  • 销售额不到10万免征什么税
  • 计提房租费
  • 奖励先进个人计划怎么写
  • nmap命令
  • 代个人多交的社保怎么查
  • 库存呆滞品处理方法
  • rtfd文件
  • 支付代销手续费缴纳增值税吗
  • 薰衣草 英国
  • laravel app接口
  • vue 使用js
  • 记账凭证和收付账簿区别
  • 税务清单和发票清单是一样吗
  • 有哪些员工福利
  • 商品流通企业商品验收入库流程
  • 小企业会计准则和企业会计准则的区别
  • 应收帐款出售给银行会计分录
  • mysql百万级数据分页查询优化
  • 什么是,利息
  • 如何设置固定资产累计折旧增值税进项税额缺损入账科目
  • 公司收取的门禁费用
  • 保险公司的奖励制度
  • 有形动产租赁属于经营租赁吗
  • 长期股权投资转让收益需要交增值税吗
  • 汽油发票怎么开专票
  • 制造费用和直接人工的关系
  • 现金日记账年结需要另起一页吗
  • 自己开发建造的房屋
  • ca证书费用计入什么科目
  • 收入的利息如何计算
  • 收到劳务费发票如何申报个税
  • 资产减值损失审计程序是什么
  • 对公帐户发票金额是什么
  • 企业清算的会计处理
  • 怎么判断win7还是win10
  • 微软官方win10启动盘
  • ubuntu 14.10
  • linux tr命令详解
  • linux解析命令
  • 无人值守安装操作系统
  • linux开启启动程序
  • linux怎么管理进程
  • 电脑显示无windows
  • cocos creatorapi
  • unity如何合并物体
  • webpack基本使用
  • js插件大全
  • dos cat命令
  • android的
  • 网页布局设计的一般步骤
  • javascript cookies
  • 搭建oj
  • python最简单
  • js制作网站
  • 深入讲解MACD:MACD红绿柱
  • js面向对象写法
  • 税务局约谈严重吗
  • 医保所属期起和所属期止
  • 辽宁省税务举报电话
  • 核准类和备案类项目
  • 税务总局纪律作风
  • 宾馆如何申请税务发票
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设