引言:

在互联网高速发展的时代里,web应用大有取代桌面应用的趋势,不必再去繁琐的安装各种软件,只需一款主流浏览器即可完成大部分常规操作,这些原因都在吸引着软件厂商和消费者。而随着各大厂商浏览器版本的迭代,前端技术的不断革新,消息推送用到的场景也越来越多了。

收发邮件提醒,在线IM聊天,自动化办公提示等等,web系统里总是能见到消息推送的应用。消息推送用好了能增强用户体验,用不好则会起相反的效果。在司空见惯的使用过程中,有没有对其中的原理产生兴趣呢?实现消息推送有N种解决方案,本文针对其中的几种,进行原理性的讲解并附有简单的代码实现。

目录:

一、什么是消息推送
二、web端的消息推送
三、实现个性化的推送

一、什么是消息推送

  • 经典场景1

当我在官网观望犹豫时,突然看到了上面消息,一位神秘的徐老板竟然爆出了麻痹戒指!!我的天,于是我果断开始了游戏!这消息很及时!

  • 经典场景2

当我拿起手机不知干嘛时收到了这条招女婿的消息.......瞬间来了精神

上述两种场景,是生活中很常见的场景,通过图文描述,应该已经清楚了推送的场景,也引出了两大推送种类,web端消息推送和移动端消息推送。接下来对消息推送进行具体的解释。

概念:

消息推送(Push)指运营人员通过自己的产品或第三方工具对用户当前网页或移动设备进行的主动消息推送。用户可以在网页上或移动设备锁定屏幕和通知栏看到push消息通知。以此来实现用户的多层次需求,使得用户能够自己设定所需要的信息频道,得到即时消息,简单说就是一种定制信息的实现方式。我们平时浏览邮箱时突然弹出消息提示收到新邮件就属于web端消息推送,在手机锁屏上看到的微信消息等等都属于APP消息推送。

二、web端的消息推送

这一章节主要对几种消息推送的方式进行原理性的讲解,并贴出简单实现的代码。

主要介绍其中的五种实现方式:短轮询、Comet、Flash XMLSocket、Server-sent、WebSocket。

1、短轮询

指在特定的的时间间隔(如每10秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客户端的浏览器。浏览器做处理后进行显示。无论后端此时是否有新的消息产生,都会进行响应。字面上看,这种方式是最简单的。这种方式的优点是,后端编写非常简单,逻辑不复杂。但是缺点是请求中大部分中是无用的,浪费了带宽和服务器资源。总结来说,简单粗暴,适用于小型(偷懒)应用。

基于Jquery的ajax前端代码:

  1. <body>

  2. <div id="push"></div>

  3. <script>

  4. $(function () {

  5. setInterval(function () {

  6. getMsg(function (res) {

  7. $("#push").append("<p>" + res +"</p>");

  8. })

  9. },10000);

  10. });

  11. function getMsg(handler){

  12. $.ajax({

  13. url:"/ShortPollingServlet",

  14. type:"post",

  15. success:function (res) {

  16. handler(res)

  17. }

  18. });

  19. }

  20. </script>

  21. </body>

servlet简单实现后端代码:

  1. public class ShortPollingServlet extends HttpServlet {

  2. public static int count = 0;

  3. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

  4. //模拟业务代码

  5. count++;

  6. response.getWriter().print("msg:" + count );

  7. }

  8. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

  9. doPost(request,response);

  10. }

  11. }

2、Comet

包括了长轮询和长连接,长轮询是客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求;长连接是在页面中的iframe发送请求到服务端,服务端hold住请求并不断将需要返回前端的数据封装成调用javascript函数的形式响应到前端,前端不断收到响应并处理。Comet的实现原理和短轮询相比,很明显少了很多无用请求,减少了带宽压力,实现起来比短轮询复杂一丢丢。比用短轮询的同学有梦想时,就可以用Comet来实现自己的推送。

长轮询的优点很明显,在无消息的情况下不会频繁的请求,耗费资小并且实现了服务端主动向前端推送的功能,但是服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。WebQQ(好像挂了)就是这样实现的。

基于Jquery的ajax前端代码:

  1. <body>

  2. <div id="push"></div>

  3. <script>

  4. $(function () {

  5. getMsg();

  6. });

  7. function getMsg() {

  8. $.ajax({

  9. url:"/LongPollingServlet",

  10. type:"post",

  11. success:function (res) {

  12. $("#push").append("<p>" + res +"</p>");

  13. getMsg();

  14. }

  15. });

  16. }

  17. </script>

  18. </body>

servlet简单实现后端代码:

  1. public class LongPollingServlet extends HttpServlet {

  2. public static int count = 0;

  3. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

  4. count++;

  5. //睡眠时间模拟业务操作等待时间

  6. double random = Math.round(Math.random()*10);

  7. long sleepTime = new Double(random).longValue();

  8. try{

  9. Thread.sleep(sleepTime*1000);

  10. response.getWriter().print("msg:" + count + " after " + sleepTime + "seconds servicing");

  11. }catch (Exception e){

  12. e.printStackTrace();

  13. }

  14. }

  15. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

  16. doPost(request,response);

  17. }

  18. }

长连接优点是消息即是到达,不发无用请求,管理起来也相对方便。缺点是服务端维护一个长连接会增加开销。比如Gmail聊天(没用过)就是这样实现的。

基于Jquery的ajax前端代码:

  1. <head>

  2. <title>pushPage</title>

  3. <script type="text/javascript">

  4. function loadData(msg) {

  5. var newChild = document.createElement("p");

  6. newChild.innerHTML = msg;

  7. document.getElementById("push").appendChild(newChild);

  8. }

  9. </script>

  10. </head>

  11. <body>

  12. <div id="push"></div>

  13. <iframe src="/LongConnServlet" frameborder="0" name="longConn"></iframe>

  14. </body>

servlet简单实现后端代码:

  1. public class LongConnServlet extends HttpServlet {

  2. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

  3. boolean flag = true;

  4. int i = 0;

  5. while (flag){

  6. try {

  7. //模拟每1秒查询一次数据库,看是否有新的消息可以推送

  8. Thread.sleep(1*1000);

  9. }catch (Exception e){

  10. e.printStackTrace();

  11. }

  12. String pushMsg = "push msg : " + i;

  13. response.setContentType("text/html;charset=GBK");

  14. response.getWriter().write("<script type='text/javascript'>parent.loadData('" + pushMsg + "')</script>");

  15. response.flushBuffer();

  16. i++;

  17. if(i==5){

  18. flag = false;

  19. }

  20. }

  21. }

  22. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

  23. doPost(request,response);

  24. }

  25. }

3、Flash XMLSocket

在 HTML 页面中内嵌入一个使用了 XMLSocket 类的 Flash 程序。JavaScript 通过调用此 Flash 程序提供的socket接口与服务器端的socket进行通信。JavaScript 在收到服务器端以 XML 格式传送的信息后可以很容易地控制 HTML 页面的内容显示。

原理示意图
利用Flash XML Socket实现”服务器推”技术前提:
(1)Flash提供了XMLSocket类,服务器利用Socket向Flash发送数据;
(2)JavaScript和Flash的紧密结合JavaScript和Flash可以相互调用。
优点是实现了socket通信,不再利用无状态的http进行伪推送。但是缺点更明显:
1.客户端必须安装 Flash 播放器;
2.因为 XMLSocket 没有 HTTP 隧道功能,XMLSocket 类不能自动穿过防火墙;
3.因为是使用套接口,需要设置一个通信端口,防火墙、代理服务器也可能对非 HTTP 通道端口进行限制。
这种方案在一些网络聊天室,网络互动游戏中已得到广泛使用。不进行代码示例。

4、Server-sent

服务器推指的是HTML5规范中提供的服务端事件EventSource,浏览器在实现了该规范的前提下创建一个EventSource连接后,便可收到服务端的发送的消息,实现一个单向通信。客户端进行监听,并对响应的信息处理显示。该种方式已经实现了服务端主动推送至前端的功能。优点是在单项传输数据的场景中完全满足需求,开发人员扩展起来基本不需要改后端代码,直接用现有框架和技术就可以集成。

基于HTML5的Server-sent事件:

  1. <head>

  2. <title>Title</title>

  3. <script>

  4. var source = new EventSource("/ServerSentServlet");//创建一个新的 EventSource对象,

  5. source.onmessage = function (evt) {//每接收到一次更新,就会发生 onmessage事件

  6. var newChild = document.createElement("p");

  7. newChild.innerHTML = evt.data;

  8. document.getElementById("push").appendChild(newChild);

  9. }

  10. </script>

  11. </head>

  12. <body>

  13. <div id="push"></div>

  14. </body>

servlet简单实现后端代码:

  1. public class ServerSentServlet extends HttpServlet {

  2. public static int count = 0;

  3. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

  4. count++;

  5. response.setCharacterEncoding("UTF-8");

  6. response.setHeader("Content-Type", "text/event-stream");//设置服务器端事件流

  7. response.setHeader("Cache-Control","no-cache");//规定不对页面进行缓存

  8. response.setHeader("Pragma","no-cache");

  9. response.setDateHeader("Expires",0);

  10. PrintWriter pw = response.getWriter();

  11. pw.println("retry: 5000"); //设置请求间隔时间

  12. pw.println("data: " + "msg:" + count +"\n\n");

  13. }

  14. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

  15. doPost(request,response);

  16. }

  17. }

5、WebSocket

WebSocket是HTML5下一种新的协议,是基于TCP的应用层协议,只需要一次连接,便可以实现全双工通信,客户端和服务端可以相互主动发送消息。客户端进行监听,并对响应的消息处理显示。这个技术相信基本都听说过,就算没写过代码,也大概知道干嘛的。通过名字就能知道,这是一个Socket连接,一个能在浏览器上用的Socket连接。是HTML5标准中的一个内容,浏览器通过javascript脚本手动创建一个TCP连接与服务端进行通讯。优点是双向通信,都可以主动发送消息,既可以满足“问”+“答”的响应机制,也可以实现主动推送的功能。缺点就是编码相对来说会多点,服务端处理更复杂(我觉得当一条有情怀的咸鱼就应该用这个!)。

前端代码:

  1. <body>

  2. <div id="push"></div>

  3. </body>

  4. <script>

  5. $(function () {

  6. var webSocket = new WebSocket("ws://localhost:8080/ws");

  7. webSocket.onmessage = function (ev) {

  8. $("#push").append("<p>" + ev.data +"</p>");

  9. }

  10. })

  11. </script>

基于注解简单实现后端代码:

  1. @ServerEndpoint("/ws")

  2. public class MyWebSocket {

  3. private Session session;

  4. public MyWebSocket() {

  5. }

  6. @OnOpen

  7. public void onOpen(Session session) {

  8. this.session = session;

  9. System.out.println("someone connect");

  10. int count = 1;

  11. while (count<=5){

  12. //睡眠时间模拟业务操作等待时间

  13. double random = Math.round(Math.random()*10);

  14. long sleepTime = new Double(random).longValue();

  15. try {

  16. Thread.sleep(sleepTime*1000);

  17. session.getBasicRemote().sendText("msg:" + count +" from server after" + sleepTime + " seconds");

  18. }catch (Exception e){

  19. e.printStackTrace();

  20. }

  21. count++;

  22. }

  23. }

  24. @OnError

  25. public void onError(Throwable t){

  26. System.out.println("something error");

  27. }

  28. }

以上是对五种推送方式原理的简单讲解和代码的实现。

三、实现个性化的推送

上面说了很多原理,也给出了简单的代码实现,但是在实际生产过程中,肯定不能用上面的代码,针对自己系统的应用场景选择合适的推送方案才是合理的,因此最后简单说一下实现个性化推送的两种方式。第一种很简单,直接使用第三方实现的推送,无需复杂的开发运维,直接可以使用。第二种就是自己封装,可以选择如今较为火热的WebSocket来实现系统的推送。

1、第三方

关于第三方推送平台,GoEasy。

推荐理由是GoEasy的理念符合我们的选择

(1)更简单的方式将消息从服务器端推送至客户端
(2)更简单的方式将消息从各种客户端推送至客户端

GoEasy具体的使用方式这里不再赘述,详见官网。对于后端后端开发者,可直接使用Rest方式调用推送,对于前端或web开发者,可以从web客户端用javascript脚本进行调用推送。

2、封装自己的推送服务(总结就是对于真的想开发的还是websocket吧!)

如果是一个老系统进行扩展,那么更推荐使用Server-sent,服务端改动量不会很大。如果是新系统,更推荐websocket,实现的功能功能更全面。

我们以websocket为例,不再贴出具体的代码实现。

我们如果需要使用websocket技术实现自己的推送服务,需要注意哪些点,或者说需要踩哪些坑呢,列出几点供大家参考:

长连接的心跳处理;
从WebSocket中获取HttpSession进行用户相关操作;
服务端调优实现高并发量client同时在线;
服务端维持多用户的状态;
群发消息;
等等等….

关于WebSocket开发关注下篇,谢谢

关于web端的消息推送方式转载相关推荐

  1. WEB即时通讯/消息推送

    写在前面 通常进行的Web开发都是由客户端主动发起的请求,然后服务器对请求做出响应并返回给客户端.但是在很多情况下,你也许会希望由服务器主动对客户端发送一些数据. 那么,该如何实现这个需求,或者说该如 ...

  2. 浅析即时通讯开发中移动端实时消息推送技术

    实时消息推送在移动端互联网时代很平常,也很重要,它的存在让智能终端真正成为全时信息传播的工具.本文将从移动端无线网络的特点来谈谈实时消息推送的技术原理及相关问题,希望能给你带来些许启发. 移动端实时消 ...

  3. SignalR 中丰富多彩的消息推送方式

    在上一篇 SignalR 文章中,演示了如何通过 SignalR 实现了简单的聊天室功能:本着简洁就是美的原则,这一篇我们也来聊聊在 SignalR 中的用户和组的概念,理解这些基础知识有助于更好的开 ...

  4. java服务端统一消息推送(苹果, 华为, 小米, 极光,vivo)

    1. 引入依赖 <!-- 极光 --> <dependency><groupId>cn.jpush.api</groupId><artifactI ...

  5. 智能分析网关微信端告警消息推送的开发流程

    智能分析网关是TSINGSEE青犀视频研发的AI边缘计算智能硬件设备,它具有AI智能检测与识别的能力,可对视频及图像中的人.车.物体.行为等进行检测识别与定位.追踪.统计,具体可包括人脸检测与识别.车 ...

  6. python+win10toast—实现PC端通知栏消息推送

    import time from win10toast import ToastNotifierdef pc_toast():toaster = ToastNotifier()header = &qu ...

  7. java 消息推送的几种方式比较

    引言: 在互联网高速发展的时代里,web应用大有取代桌面应用的趋势,不必再去繁琐的安装各种软件,只需一款主流浏览器即可完成大部分常规操作,这些原因都在吸引着软件厂商和消费者.而随着各大厂商浏览器版本的 ...

  8. web中的GoEasy消息推送机制

    最近要用到消息推送机制,网上查了很多,什么websocket,pushlet,GoEasy等,最后发现还是GoEasy最简单方便,很容易入手,不到10分钟就可以进行web端的消息推送啦 话不多说,直接 ...

  9. 未读消息(小红点),前端 与 RabbitMQ 实时消息推送实践,贼简单~

    前几天粉丝群里有个小伙伴问过:web 页面的未读消息(小红点)怎么实现比较简单,刚好本周手头有类似的开发任务,索性就整理出来供小伙伴们参考,没准哪天就能用得上呢. 之前在 <springboot ...

最新文章

  1. 智慧城市领域又出最新报告——智慧交通将迎来大爆发
  2. windows Server 2003   IIS启用父路径
  3. sparkmllib scala GBDT Demo
  4. PTA-1022——Digital Library
  5. 007--C++动态内存(数组)
  6. 在Java应用程序中使用密码学
  7. 两个经典的Oracle触发器示例
  8. 聚集索引表插入数据和删除数据的方式是怎样的
  9. 英国通讯服务商与采购“不公平待遇”的较量
  10. python两个函数中传递变量_如何在Python中向函数传递大量变量?
  11. 超分辨率重建测试(DASR)
  12. PDF怎么转CAD?分享两种转换方法
  13. JavaScript 重定向
  14. 一款免费好用的在线高效作图工具
  15. GIS的下个十年(Cary Mann, vice president, Bentley)
  16. android 工具 拓扑图,GitHub - AndroidHelper/graph.editor: HTML5拓扑图编辑器
  17. Java平台,标准版Oracle JDK 9中的新功能
  18. 【天嵌分享活动】E9卡片电脑设置显示屏分辨率
  19. 《人力资源管理》在线作业
  20. java tsp 遗传算法_遗传算法解决TSP问题

热门文章

  1. 各类查询:违章、车辆资料、驾驶员资料
  2. TP 通过STMP发送Email邮件
  3. 什么是编程编程都是做什么的
  4. 什么是网络安全(上)
  5. 数据架构师 VS 数据工程师,薪酬平均3万+,区别在哪里
  6. HTML怎么引用QQ相册的照片,qq空间照片打不开 为什么QQ空间里的相册打不开?
  7. windows:QuickLook实现文件预览
  8. 初链--新一代混合共识公链技术心得
  9. 解题报告 URAL 1051
  10. CarsimVeristand联合仿真系列-环境搭建01