应用办公生活信息教育商业
投稿投诉
商业财经
汽车智能
教育国际
房产环球
信息数码
热点科技
生活手机
晨报新闻
办公软件
科学动态
应用生物
体育时事

WEB实时消息推送这7种方案能更好地帮你实现

  前言
  我有一个朋友(手动狗头)
  做了一个小破站,现在要实现一个站内信web消息推送的功能,对,就是下图这个小红点,一个很常用的功能。
  不过他还没想好用什么方式做,这里我帮他整理了一下几种方案,并简单做了实现。
  什么是消息推送(push)
  推送的场景比较多,比如有人关注我的公众号,这时我就会收到一条推送消息,以此来吸引我点击打开应用。
  消息推送(push)通常是指网站的运营工作等人员,通过某种工具对用户当前网页或移动设备APP进行的主动消息推送。
  消息推送一般又分为web端消息推送和移动端消息推送。
  上边的这种属于移动端消息推送,web端消息推送常见的诸如站内信、未读邮件数量、监控报警数量等,应用得也非常广泛。
  在具体实现之前,咱们再来分析一下前边的需求,其实功能很简单,只要触发某个事件(主动分享了资源或者后台主动推送消息),web页面的通知小红点就会实时的1就可以了。
  通常在服务端会有若干张消息推送表,用来记录用户触发不同事件所推送不同类型的消息,前端主动查询(拉)或者被动接收(推)用户所有未读的消息数。
  消息推送无非是推(push)和拉(pull)两种形式,下边我们逐个了解下。短轮询
  轮询(polling)应该是实现消息推送方案中最简单的一种,这里我们暂且将轮询分为短轮询和长轮询。
  短轮询很好理解,指定的时间间隔,由浏览器向服务器发出HTTP请求,服务器实时返回未读消息数据给客户端,浏览器再做渲染显示。
  一个简单的JS定时器就可以搞定,每秒钟请求一次未读消息数接口,返回的数据展示即可。setInterval((){方法请求messageCount()。then((res){if(res。code200){this。messageCountres。data}})},1000);复制代码
  效果还是可以的,短轮询实现固然简单,缺点也是显而易见,由于推送数据并不会频繁变更,无论后端此时是否有新的消息产生,客户端都会进行请求,势必会对服务端造成很大压力,浪费带宽和服务器资源。
  长轮询
  长轮询是对上边短轮询的一种改进版本,在尽可能减少对服务器资源浪费的同时,保证消息的相对实时性。长轮询在中间件中应用的很广泛,比如Nacos和apollo配置中心,消息队列kafka、RocketMQ中都有用到长轮询。
  Nacos配置中心交互模型是push还是pull?一文中我详细介绍过Nacos长轮询的实现原理,感兴趣的小伙伴可以瞅瞅。
  这次我使用apollo配置中心实现长轮询的方式,应用了一个类DeferredResult,它是在servelet3。0后经过Spring封装提供的一种异步请求机制,直意就是延迟结果。
  DeferredResult可以允许容器线程快速释放占用的资源,不阻塞请求线程,以此接受更多的请求提升系统的吞吐量,然后启动异步工作线程处理真正的业务逻辑,处理完成调用DeferredResult。setResult(200)提交响应结果。
  下边我们用长轮询来实现消息推送。
  因为一个ID可能会被多个长轮询请求监听,所以我采用了guava包提供的Multimap结构存放长轮询,一个key可以对应多个value。一旦监听到key发生变化,对应的所有长轮询都会响应。前端得到非请求超时的状态码,知晓数据变更,主动查询未读消息数接口,更新页面数据。ControllerRequestMapping(polling)publicclassPollingController{存放监听某个Id的长轮询集合线程同步结构publicstaticMultimapString,DeferredResultStringwatchRequestsMultimaps。synchronizedMultimap(HashMultimap。create());设置监听GetMapping(pathwatch{id})ResponseBodypublicDeferredResultStringwatch(PathVariableStringid){延迟对象设置超时时间DeferredResultStringdeferredResultnewDeferredResult(TIMEOUT);异步请求完成时移除key,防止内存溢出deferredResult。onCompletion((){watchRequests。remove(id,deferredResult);});注册长轮询请求watchRequests。put(id,deferredResult);returndeferredResult;}变更数据GetMapping(pathpublish{id})ResponseBodypublicStringpublish(PathVariableStringid){数据变更取出监听ID的所有长轮询请求,并一一响应处理if(watchRequests。containsKey(id)){CollectionDeferredResultStringdeferredResultswatchRequests。get(id);for(DeferredResultStringdeferredResult:deferredResults){deferredResult。setResult(我更新了newDate());}}returnsuccess;}复制代码
  当请求超过设置的超时时间,会抛出AsyncRequestTimeoutException异常,这里直接用ControllerAdvice全局捕获统一返回即可,前端获取约定好的状态码后再次发起长轮询请求,如此往复调用。ControllerAdvicepublicclassAsyncRequestTimeoutHandler{ResponseStatus(HttpStatus。NOTMODIFIED)ResponseBodyExceptionHandler(AsyncRequestTimeoutException。class)publicStringasyncRequestTimeoutHandler(AsyncRequestTimeoutExceptione){System。out。println(异步请求超时);return304;}}复制代码
  我们来测试一下,首先页面发起长轮询请求pollingwatch10086监听消息更变,请求被挂起,不变更数据直至超时,再次发起了长轮询请求;紧接着手动变更数据pollingpublish10086,长轮询得到响应,前端处理业务逻辑完成后再次发起请求,如此循环往复。
  长轮询相比于短轮询在性能上提升了很多,但依然会产生较多的请求,这是它的一点不完美的地方。iframe流
  iframe流就是在页面中插入一个隐藏的复制代码codepre
  服务端直接组装html、js脚本数据向response写入就行了ControllerRequestMapping(iframe)publicclassIframeController{GetMapping(pathmessage)publicvoidmessage(HttpServletResponseresponse)throwsIOException,InterruptedException{while(true){response。setHeader(Pragma,nocache);response。setDateHeader(Expires,0);response。setHeader(CacheControl,nocache,nostore);response。setStatus(HttpServletResponse。SCOK);response。getWriter()。print();}}}复制代码
  但我个人不推荐,因为它在浏览器上会显示请求未加载完,图标会不停旋转,简直是强迫症杀手。
  SSE(我的方式)
  很多人可能不知道,服务端向客户端推送消息,其实除了可以用WebSocket这种耳熟能详的机制外,还有一种服务器发送事件(Serversentevents),简称SSE。
  SSE它是基于HTTP协议的,我们知道一般意义上的HTTP协议是无法做到服务端主动向客户端推送消息的,但SSE是个例外,它变换了一种思路。
  SSE在服务器和客户端之间打开一个单向通道,服务端响应的不再是一次性的数据包而是texteventstream类型的数据流信息,在有数据变更时从服务器流式传输到客户端。
  整体的实现思路有点类似于在线视频播放,视频流会连续不断地推送到浏览器,你也可以理解成,客户端在完成一次用时很长(网络不畅)的下载。
  SSE与WebSocket作用相似,都可以建立服务端与浏览器之间的通信,实现服务端向客户端推送消息,但还是有些许不同:SSE是基于HTTP协议的,它们不需要特殊的协议或服务器实现即可工作;WebSocket需单独服务器来处理协议。SSE单向通信,只能由服务端向客户端单向通信;webSocket全双工通信,即通信的双方可以同时发送和接受信息。SSE实现简单开发成本低,无需引入其他组件;WebSocket传输数据需做二次解析,开发门槛高一些。SSE默认支持断线重连;WebSocket则需要自己实现。SSE只能传送文本消息,二进制数据需要经过编码后传送;WebSocket默认支持传送二进制数据。
  SSE与WebSocket该如何选择?
  技术并没有好坏之分,只有哪个更合适
  SSE好像一直不被大家所熟知,一部分原因是出现了WebSockets,这个提供了更丰富的协议来执行双向、全双工通信。对于游戏、即时通信以及需要双向近乎实时更新的场景,拥有双向通道更具吸引力。
  但是,在某些情况下,不需要从客户端发送数据。而你只需要一些服务器操作的更新。比如:站内信、未读消息数、状态更新、股票行情、监控数量等场景,SEE不管是从实现的难易和成本上都更加有优势。此外,SSE具有WebSockets在设计上缺乏的多种功能,例如:自动重新连接、事件ID和发送任意事件的能力。
  前端只需进行一次HTTP请求,带上唯一ID,打开事件流,监听服务端推送的事件就可以了复制代码
  服务端的实现更简单,创建一个SseEmitter对象放入sseEmitterMap进行管理privatestaticMapString,SseEmittersseEmitterMapnewConcurrentHashMap();创建连接date:202271214:51auther:公123publicstaticSseEmitterconnect(StringuserId){try{设置超时时间,0表示不过期。默认30秒SseEmittersseEmitternewSseEmitter(0L);注册回调sseEmitter。onCompletion(completionCallBack(userId));sseEmitter。onError(errorCallBack(userId));sseEmitter。onTimeout(timeoutCallBack(userId));sseEmitterMap。put(userId,sseEmitter);count。getAndIncrement();returnsseEmitter;}catch(Exceptione){log。info(创建新的sse连接异常,当前用户:{},userId);}returnnull;}给指定用户发送消息date:202271214:51auther:123publicstaticvoidsendMessage(StringuserId,Stringmessage){if(sseEmitterMap。containsKey(userId)){try{sseEmitterMap。get(userId)。send(message);}catch(IOExceptione){log。error(用户〔{}〕推送异常:{},userId,e。getMessage());removeUser(userId);}}}复制代码
  我们模拟服务端推送消息,看下客户端收到了消息,和我们预期的效果一致。
  注意:SSE不支持IE浏览器,对其他主流浏览器兼容性做的还不错。
  MQTT
  什么是MQTT协议?
  MQTT全称(MessageQueueTelemetryTransport):一种基于发布订阅(publishsubscribe)模式的轻量级通讯协议,通过订阅相应的主题来获取消息,是物联网(InternetofThing)中的一个标准传输协议。
  该协议将消息的发布者(publisher)与订阅者(subscriber)进行分离,因此可以在不可靠的网络环境中,为远程连接的设备提供可靠的消息服务,使用方式与传统的MQ有点类似。
  TCP协议位于传输层,MQTT协议位于应用层,MQTT协议构建于TCPIP协议上,也就是说只要支持TCPIP协议栈的地方,都可以使用MQTT协议。
  为什么要用MQTT协议?
  MQTT协议为什么在物联网(IOT)中如此受偏爱?而不是其它协议,比如我们更为熟悉的HTTP协议呢?首先HTTP协议它是一种同步协议,客户端请求后需要等待服务器的响应。而在物联网(IOT)环境中,设备会很受制于环境的影响,比如带宽低、网络延迟高、网络通信不稳定等,显然异步消息协议更为适合IOT应用程序。HTTP是单向的,如果要获取消息客户端必须发起连接,而在物联网(IOT)应用程序中,设备或传感器往往都是客户端,这意味着它们无法被动地接收来自网络的命令。通常需要将一条命令或者消息,发送到网络上的所有设备上。HTTP要实现这样的功能不但很困难,而且成本极高。
  具体的MQTT协议介绍和实践,这里我就不再赘述了,大家可以参考我之前的两篇文章,里边写的也都很详细了。
  MQTT协议的介绍
  我也没想到springbootrabbitmq做智能家居,会这么简单
  MQTT实现消息推送
  未读消息(小红点),前端与RabbitMQ实时消息推送实践,贼简单Websocket
  websocket应该是大家都比较熟悉的一种实现消息推送的方式,上边我们在讲SSE的时候也和websocket进行过比较。
  WebSocket是一种在TCP连接上进行全双工通信的协议,建立客户端和服务器之间的通信渠道。浏览器和服务器仅需一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
  springboot整合websocket,先引入websocket相关的工具包,和SSE相比额外的开发成本。!引入websocketdependencygroupIdorg。springframework。bootgroupIdspringbootstarterwebsocketartifactIddependency复制代码
  服务端使用ServerEndpoint注解标注当前类为一个websocket服务器,客户端可以通过ws:localhost:7777webSocket10086来连接到WebSocket服务器端。ComponentSlf4jServerEndpoint(websocket{userId})publicclassWebSocketServer{与某个客户端的连接会话,需要通过它来给客户端发送数据privateSessionsession;privatestaticfinalCopyOnWriteArraySetWebSocketServerwebSocketsnewCopyOnWriteArraySet();用来存在线连接数privatestaticfinalMapString,SessionsessionPoolnewHashMapString,Session();链接成功调用的方法OnOpenpublicvoidonOpen(Sessionsession,PathParam(valueuserId)StringuserId){try{this。sessionsession;webSockets。add(this);sessionPool。put(userId,session);log。info(websocket消息:有新的连接,总数为:webSockets。size());}catch(Exceptione){}}收到客户端消息后调用的方法OnMessagepublicvoidonMessage(Stringmessage){log。info(websocket消息:收到客户端消息:message);}此为单点消息publicvoidsendOneMessage(StringuserId,Stringmessage){SessionsessionsessionPool。get(userId);if(session!nullsession。isOpen()){try{log。info(websocket消:单点消息:message);session。getAsyncRemote()。sendText(message);}catch(Exceptione){e。printStackTrace();}}}}复制代码
  前端初始化打开WebSocket连接,并监听连接状态,接收服务端数据或向服务端发送数据。复制代码
  页面初始化建立websocket连接,之后就可以进行双向通信了,效果还不错
  自定义推送
  上边我们给我出了6种方案的原理和代码实现,但在实际业务开发过程中,不能盲目的直接拿过来用,还是要结合自身系统业务的特点和实际场景来选择合适的方案。
  推送最直接的方式就是使用第三推送平台,毕竟钱能解决的需求都不是问题,无需复杂的开发运维,直接可以使用,省时、省力、省心,像goEasy、极光推送都是很不错的三方服务商。
  一般大型公司都有自研的消息推送平台,像我们本次实现的web站内信只是平台上的一个触点而已,短信、邮件、微信公众号、小程序凡是可以触达到用户的渠道都可以接入进来。
  消息推送系统内部是相当复杂的,诸如消息内容的维护审核、圈定推送人群、触达过滤拦截(推送的规则频次、时段、数量、黑白名单、关键词等等)、推送失败补偿非常多的模块,技术上涉及到大数据量、高并发的场景也很多。所以我们今天的实现方式在这个庞大的系统面前只是小打小闹。Github地址
  文中所提到的案例我都一一的做了实现,整理放在了Github上,觉得有用就Star一下吧!
  传送门:github。comchengxynds
  原文:https:juejin。cnpost7122014462181113887

新四板挂牌是什么意思(新四板股票怎么买)主板、中小板、创业板以及场外市场想必大家都听说过,但是对于新四板,不知道大家了解不了解呢?【什么是新四板】首先,新四板是在新三板的基础上推出的,是前海股权交易中心推……肾病知识科普得了肾脏病,多喝水还是少喝水?每人每天至少要消耗1。5公升的水份,而每天我们吃下的食物中当中,有些已经含有大量的水份,像日常中喝的汤水、蔬菜、水果等都有一定的水份含量。因此,要依据每个人的活动量决定喝水分量……印度神油皇帝油代理市场前景好吗?有哪些作用?针对当前的微商市场现状,不难发现与健康相关的产品更有发展潜力。这也是为什么印度神油皇帝油能够如此火爆的原因。印度神油皇帝油是一款效果非常显著的产品,安全有效,自从上市就引发了热……杜锋任性!强留吴前队友,场均93挤走沙拉木,比于德豪受宠6月24日,中国男篮国家队正式公布了出征世预赛的名单,已经入选的球员即将奔赴澳大利亚,参加之后的比赛。这次杜锋召集了19人集训,最终吴前、范子铭、阿不都沙拉木、王奕博、高诗岩离……迪丽热巴的十年,从女配到流量小花,新疆美人的开挂之路你看,我是一个灯,我本来就是一个灯嘛这句经典喝醉酒台词,让许多人记住了《克拉恋人》中的女二高雯,也让许多人恍然大悟。原来女神也可以这么搞笑,这个角色甚至还被称之为中……长途搬家用什么物流(跨省搬家大件行李邮寄)工厂有批货从深圳始发到郑州,跨省寄大件物流怎么划算又靠谱,小美告诉你跨省寄大件物流选哪家公司?深圳的传统物流公司美泰物流网物流带你走进跨省寄大件物流。看看这里你就知道了。……西甲第1轮前瞻皇马志在卫冕巴萨渴望开门红202223赛季的西甲联赛已经准备就绪,即将到来的周六、周日、周一和周二将上演精彩的第一轮。皇马,巴萨和马竞是上赛季的前三名,不过他们将无法轻松进入这个新赛季,因为在首周将会面……人为什么会变老(女性抗衰老最好的方法)女性在生完孩子之后,身体衰老的非常快,但有没有什么方法缓解衰老呢?就让小编给大家介绍几种方法!合理补充雌性激素雌性激素是女性的一把保护伞,维持心血管、骨骼、神经和泌……电是什么时候发明的(中国最早的照相机)首先文章开头先提一个问题,电是什么?电是什么电这种东西吧,看不见摸不着,但是我们又离不开它,我们也很难用,一句话清晰地概括出它到底是某种物质呢还是某种现象。这期我们……快递员怎么样(快递员属于什么工作单位)快递员小刘向自己的好朋友小赵抱怨道,现在送快递太累了,等我赚到钱了,就不想继续做了。进一步了解了之后,小赵才知道,快递员的工资主要由两部分构成,底薪加上提成。快递员又苦又……林子祥和叶倩文结婚25年后,林子祥75岁了变化不大,她却像换到了一定年龄,还没有找到属于自己的幸福,不止普通人会焦虑,明星也会焦虑。叶倩文是我们耳熟能详的一位天后级的歌手。她的声音嘹亮,歌曲细腻,从而让人产生共鸣。她和……非布司他治疗痛风价格多少钱一瓶,效果好吗?很多人患痛风之后,都承受了很多的痛苦。尤其是尿酸高的痛风人群,那种痛苦真的是非常难熬。相信痛风患者都知道,治疗痛风要从止痛、降低尿酸以及碱化尿液这三个方面入手。而降低尿酸是最重……
儿子请原谅爸爸,爸爸也是第一次学着当爸爸?有人说,成长是一个漫长的过程;有点复杂、有点悠长。而有的时候,它却是一瞬间就能完成的事情。是啊,孩子总是在不经意间就长大,也许他准备好了,但做父母的你有没有准备好呢?……锌元素缺乏和过量的危害,怎么正确摄取呢?矿物质是除有机化合物和水以外的元素,包括常量元素和微量元素。常量元素指的是体内含量大于体重0。01的元素,包括钙、镁、钾、钠、磷、硫、氯;微量元素指的是体内含量低于人体体重0。……顿悟!百度强推的Redis天花板笔记,原来数据库是这样理解的前言在目前的技术选型中,Redis俨然已经成为了系统高性能缓存方案的事实标准,因此现在Redis也成为了后端开发的基本技能树之一。基于上述情况,今天给大家分享一份我……篮网到底该何去何从?三大垃圾绝不能留,杜兰特该承担起更多责任要说本赛季哪支球队最让球迷们失望,布鲁克林篮网队绝对榜上有名,在拥有杜兰特、欧文、格里芬、阿尔德里奇,甚至前期还有哈登的情况下,篮网队最终在季后赛首轮就被绿军横扫出局,而且需要……第一波动力锂电池退役潮来临,每个电池都是活的?不知不觉9年过去了,从2012年中国新能源汽车大规模上市,到如今大街小巷随处可见的电动汽车。截至2021年中国已经累计出售560多万辆电动汽车。然而,随着时间的推移,如今……抓卫星!中国实践二十一号将北斗卫星抓到墓地轨道,美国需规范2022年1月27日,美国《太空新闻》(spacenews。com)报道:1月22日,中国实践21号卫星成功捕获了失效的北斗2号G2卫星,1月26日将其拖到墓地轨道后,自己又回……小米12系列首销突破18亿,小米12和小米12Pro是主力,进入2022年的前一天,小米12系列正式开启首销,根据小米官方发布的首销战报显示,小米12系列开售5分钟,销售额便达到了18亿元,这其中主要包括小米12X、小米12和小米12P……茶油里的山茶甙是什么东西?它的作用,超乎你的想象山茶油,是我国特有的一种食用植物油,其历史能追溯到几千年以前,从古至今都是我们生活中不可缺少的食用油,只是因为它地域限制的原因,只能在南方生长,所以北方的朋友才见得比较少。……狼队首发输给eStar二队后,迎来一项重大好消息,春季赛要夺在2021年的KPL春季赛,很多玩家认为武汉eStar和狼队是最强的两支队伍,他们在常规赛阶段也是分列一二名。在季后赛中,虽然狼队输给了TTG,但狼队是唯一一支跟eStar打到……女婴出生自带胎记家长没在意,2个月后却被诊断为重症,让人崩溃对于大多数人而言,所谓的幸福是年迈父母脸上的一抹笑,或是孩子所喊出来的一声爸妈。对于彭明月而言,她的幸福却是祈求老天让1岁多的女儿,能健康平安地活下去。看着几个大人摁压着……17偷袭4AM被全员反扑,XDD被队友车技坑惨,PCL都在玩要说这么多场PCL职业赛场,大多数队伍都是不断转变,有的从一支默默无闻改为的正面钢枪,从钢枪拿分到目前的运营排名。虽然有不断的新鲜血液进入赛场,老牌强队除了感受新人带来的压力,……加量又降价!华为MateXs2售9999!网友华为独占市场差华为对折叠屏产品进行了更新,推出了华为MateXs2这款产品,这款产品是一款外折类型的折叠屏,也就是说华为目前要对内折、外折以及小屏折叠屏三种形态进行更新。折叠屏手机兴起的这几……
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网