服务器推送消息至浏览器(记录–服务端推送到Web前端有哪几种方式?)
这里给大家分享我在网上总结出来的一些知识 ,希望对大家有所帮助
其中的代码也上传到GitHub了 ,在server-push( github.com/waiter/serv… )这里 。
各种方案
从上面的截图也已经可以看出 ,本文主要写了5种方案 ,那么接下来也就一个一个简单介绍一下吧 。
另外 ,本文涉及的Demo ,后端直接使用原生的Node.js开发 ,没有使用Koa 、Express之类的 ,也没有使用额外的库 ,类似socket.io ,主要是想保持最精简的状态来呈现 。前端也只是在最基础的HTML上 ,引入了jQuery来方便做DOM操作 ,也引入了Bootstrap来快速实现统一的样式,而未再引入类似Vue 、React之类的框架 。
还有 ,为了触发服务端推送 ,这边在前端页面上加了个输入框和按钮,来将消息发送给后端 ,后端会缓存消息 ,并触发推送 ,后端大体代码类似:
1. 轮询(短轮询)
这是最简单直观的方法 ,就是每隔一段时间发起一个请求到后端询问是否有新信息 。至于为什么又叫短轮询 ,其是相对于后续要说的长轮询来对比的 。
这样前端只要设置一个setTimeout来定时请求就行:
后端也是否简单 ,根据前端给到的id ,看看有没有新消息 ,有就返回 ,没有就返回空
这个看起来其实时性与请求频率成正相关 ,但是当请求频率上来了 ,性能浪费也就越高 ,毕竟可能大部分请求都是无意义的 。
2. 长轮询
在翻找资料的时候,发现有些资料会直接把这个当作短轮询 ,有点匪夷所思 。这里的长轮询相对前面的轮询来说 ,算是一种优化 。具体就是前端发起请求到后端,后端不直接返回 ,而是等待有新信息时再返回 。所以这样发起的一个请求 ,可能需要很长的时间才能等到返回 ,故而叫做长轮询 。
其前端代码基本和短轮询一致 ,只不过把请求的超时时间设置较长(比如1分钟) ,然后无论请求成功或失败 ,马上再次发起请求即可 。
相对来说 ,后端的写法就要稍微改动一下
这样 ,**相对于短轮询 ,少了很多无意义的请求 ,而且消息的实时性也非常好。**不过 ,当服务端有异常时,会导致长轮询短时间内不断发起请求 ,可能让服务端承受更大的压力 ,所以两次长轮询之间最好有一定间隔,或者异常检测机制 。
3. SSE(Server-sent events)
Traditionally, a web page has to send a request to the server to receive new data; that is, the page requests data from the server. With server-sent events, its possible for a server to send new data to a web page at any time, by pushing messages to the web page. These incoming messages can be treated as Events + data inside the web page.
前面提到的轮询 、长轮询都是一问一答式的 ,一次请求 ,无法推送多次消息到前端 。而SSE就厉害了 ,一次请求 ,N次推送。
其原理 ,或者说类比 ,个人认为可以理解为下载一个巨大的文件 ,文件的内容分块传给前端 ,每块就是一次消息推送 。
听起来很厉害 ,先看看后端代码要怎么写
后端代码很简单 ,核心在于Content-Type: text/event-stream ,这要让前端知道这是SSE ,还有就是传输信息的格式比较特别一点,详细的可以看 MDN( developer.mozilla.org/en-US/docs/… )
而前端有专门的EventSource来接收 ,使用起来很方便
这样就好了 ,如果你打开Chrome的开发者工具中的网络标签,你就会发现Chrome对于SSE请求 ,有专门的展示标签
另外 ,**SSE还支持自动重连!**服务器短时间异常 ,恢复之后 ,无需额外代码 ,SSE就自动重连上了 。不过 ,本人在实际工作中却没有碰到过SSE ,也就在面试题中见过 。
4. WebSocket
既然有了SSE ,那还要WebSocket干啥啊?因为WebSocket可以一次连接 ,双向推送 ,而SSE只能从服务端推送到前端 。从这个角度来看 ,用WebSocket来单做服务端推送 ,有点大材小用了 。
另外,初见WebSocket ,可能会对其与Socket的联系有点疑惑 。Socket协议是与HTTP协议平级的 ,而WebSocket协议是基于HTTP协议的,不过两者在使用层面上是十分相近的 。
其前端使用写法与SSE类似 ,十分简单 ,只不过请求链接为ws://或者wss://开头(相当于http://和https://)
而如果要用原生Node.js来写WebSocket服务 ,就会麻烦一些了 ,一般情况都会使用类似socket.io之类的三方库来降低实现成本 。这边也就在网上摘抄了一段代码来简单实现一下 ,详细的可以看Github上的Demo代码
这个在Chrome浏览器中 ,也有专门的标签页展示
不过 ,它没有像SSE一样有自动重连 ,这块需要自行实现 。
一般网页实时聊天之类需要双向推送的 ,都会使用WebSocket来实现 。
5. iFrame
这算是找资料的时候意外发现的 ,之前并不知道还有这样的玩法 。原理类似使用iFrame加载一个巨大的网页 ,利用浏览器会一边加载一边解析执行返回的HTML ,通过分次返回Script标签来实现消息推送 。其实现类似SSE,不过看起来就比较==hack==。
前端代码很简单 ,只不过要注册一个回调给iframe使用
而后端也很简单 ,有消息的时候返回script标签即可
相当奇淫巧技了 。不过,似乎没找到怎么判断加载异常的情况 ,可能需要自行加心跳来实现了 。
另外 ,很多文章在说使用iFrame方法时 ,会导致浏览器显示未加载完 ,图标一直转的样子。但是个人认为 ,图标一直转是因为页面一直没有onload ,那么在页面onload之后 ,再创建iFrame就应该没有这个问题了 。
总结一下
上面实现了5种推送的方案 ,弄了一个表格简单对比一下
本文转载于:
https://juejin.cn/post/7113813187727720461
如果对您有所帮助 ,欢迎您点个关注 ,我会定时更新技术文档 ,大家一起讨论学习 ,一起进步 。
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!