前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >干货 | 长连接/websocket/SSE等主流服务器推送技术比较

干货 | 长连接/websocket/SSE等主流服务器推送技术比较

作者头像
疯狂的技术宅
发布2019-03-27 15:18:41
3.1K0
发布2019-03-27 15:18:41
举报
文章被收录于专栏:京程一灯

作者简介

本文由携程市场营销研发部武艺嫱和王宇星以及张子祥共同撰写,武艺嫱在市场营销研发部负责前端,王宇星和张子祥在市场营销研发部负责java后端。

最近做的某个项目有个需求,需要实时提醒client端有线上订单消息。所以保持客户端和服务器端的信息同步是关键要素,对此我们了解了可实现的方式。本文将介绍web常用的几种方式,希望给需要服务器端推送消息的同学在选型上有一点启发。

一、推送技术常用的集中实现的实现方式

1.1 短连接轮询:

前端用定时器,每间隔一段时间发送请求来获取数据是否更新,这种方式可兼容ie和支持高级浏览器。通常采取setInterval或者setTimeout实现。

(轮询示意图)

通过递归的方法,在获取到数据后每隔一定时间再次发送请求,这样虽然无法保证两次请求间隔为指定时间,但是获取的数据顺序得到保证。

  • 缺点:

1、页面会出现‘假死’

setTimeout在等到每次EventLoop时,都要判断是否到指定时间,直到时间到再执行函数,一旦遇到页面有大量任务或者返回时间特别耗时,页面就会出现‘假死’,无法响应用户行为。

2、无谓的网络传输

当客户端按固定频率向服务器发起请求,数据可能并没有更新,浪费服务器资源。

1.2 长轮询:

客户端像传统轮询一样从服务端请求数据,服务端会阻塞请求不会立刻返回,直到有数据或超时才返回给客户端,然后关闭连接,客户端处理完响应信息后再向服务器发送新的请求。

(轮询示意图)

长轮询解决了频繁的网络请求浪费服务器资源可以及时返回给浏览器。

  • 缺点:

1、保持连接会消耗资源。

2、服务器没有返回有效数据,程序超时。

1.3 iframe流:

iframe流方式是在页面中插入一个隐藏的iframe,利用其src属性在服务器和客户端之间创建一条长连接,服务器向iframe传输数据(通常是HTML,内有负责插入信息的javascript),来实时更新页面。

  • 前端实现步骤:

1、Iframe设置为不显示。

2、src设为请求的数据地址。

3、定义个父级函数用户让iframe子页面调用传数据给父页面。

4、定义onload事件,服务器timeout后再次重新加载iframe。

  • 后端输出内容:

当有新消息时服务端会向iframe中输入一段js代码.:println("<script>父级函数('" + 数据 +"<br>')</script>”);用于调用父级函数传数据。

  • 优点:

iframe流方式的优点是浏览器兼容好,Google公司在一些产品中使用了iframe流,如Google Talk

  • 缺点:

1、IE、Mozilla Firefox会显示加载没有完成,图标会不停旋转。

2、服务器维护一个长连接会增加开销。

1.4 WebSocket:

WebSocket是一种全新的协议,随着HTML5草案的不断完善,越来越多的现代浏览器开始全面支持WebSocket技术了,它将TCP的Socket(套接字)应用在了webpage上,从而使通信双方建立起一个保持在活动状态连接通道。

  • 原理:

WebSocket协议是借用HTTP协议的101 switchprotocol(服务器根据客户端的指定,将协议转换成为 Upgrade首部所列的协议)来达到协议转换的,从HTTP协议切换成WebSocket通信协议。

  • 具体连接方式:

通过在请求头中增加 upgrade:websocket 及通信密钥(Sec-WebSocket-Key),使双方握手成功,建立全双工通信。

(WebSocket客户端连接报文)

(WebSocket服务端响应报文)

  • 通信过程:

websocket是纯事件驱动的,一旦 WebSocket 连接建立后,通过监听事件可以处理到来的数据和改变的连接状态。数据都以帧序列的形式传输。服务端发送数据后,消息和事件会异步到达。WebSocket编程遵循一个异步编程模型,只需要对WebSocket对象增加回调函数就可以监听事件。

(websocket示意图)

前端:

服务端:

1.5 Server-sent Events(sse):

sse与长轮询机制类似,区别是每个连接不只发送一个消息。客户端发送一个请求,服务端保持这个连接直到有新消息发送回客户端,仍然保持着连接,这样连接就可以消息的再次发送,由服务器单向发送给客户端。

  • 原理:

SSE本质是发送的不是一次性的数据包,而是一个数据流。可以使用 HTTP 301 和 307 重定向与正常的 HTTP 请求一样。服务端连续不断的发送,客户端不会关闭连接,如果连接断开,浏览器会尝试重新连接。如果连接被关闭,客户端可以被告知使用 HTTP 204 无内容响应代码停止重新连接。

sse只适用于高级浏览器,ie不支持。因为ie上的XMLHttpRequest对象不支持获取部分的响应内容,只有在响应完成之后才能获取其内容。

二、常用实现的对比

短轮询

长轮询

Websocket

sse

通讯方式

http

http

基于TCP长连接通讯

http

触发方式

轮询

轮询

事件

事件

优点

兼容性好容错性强,实现简单

全双工通讯协议,性能开销小、安全性高,有一定可扩展性

实现简便,开发成本低

缺点

安全性差,占较多的内存资源与请求数

安全性差,占较多的内存资源与请求数

传输数据需要进行二次解析,增加开发成本及难度

只适用高级浏览器

适用范围

b/s服务

b/s服务

网络游戏、银行交互和支付

服务端到客户端单向推送

三、项目选型

sse

websocket

轮询

服务器部署

×

×

浏览器兼容性

×

×

后端推送

×

Websocket需要服务器重新部署,sse可以利用原先的http协议,而我们项目是在高级浏览器环境,场景是需要服务器单向发送给客户端,所以sse更符合我们的需求。

四、项目实践

A应用下单完成后,把订单消息放入到redis缓存中,B应用去获取redis缓存信息判断是否是新订单,否的情况轮询redis缓存,是的情况消息推送给前端。

(后端流程图)

客户端:

然后使用onmessage事件来获取消息

服务端可以自定义类型的事件,对于这些事件,可以使用addEventListener来获取。

服务端:

内容与普通的Controller差不多。只不过相应的方法在路由配置时,将produces属性的文本类型设置成“text/event-stream”即可。

首先通过设置唯一标识符+venueid,获取相应场馆保存在redis中的订单。

常见问题及解决方案:

1、怎么确定推过来的消息是新消息

这里我们设置了一个本地缓存,用来存放上一次从redis中获取的信息,和当前从redis获取的信息做对比,不同,则认为是新信息返回给客户端并标识是新数据。

2、刷新页面原先推送过来的消息消失了

因为在通过redis和本地缓存对比的时候没有区别所以不会推送,这里前端设置一个随机数num,在存入本地缓存时key值多加了num的区分。

3、解决容器超时的问题

后端容器的单个连接超时时间为2分钟,后端每隔3秒钟会轮询一次redis,到第20次的时候,会推送个带有个标识的数据。

4、接口防刷方案

后端记录每次获取到的num值判断总数vnum,超过一定数量返回http 204断开连接。

总结

对于简单的推送需求又不考虑兼容低版本浏览器,推荐使用server-sent Events。

如果需要多条双向数据实时交互或需要二进制传输,推荐websocket。

对于还要考虑低版本浏览器,那么还是用轮询来实现功能。


往期精选文章

使用虚拟dom和JavaScript构建完全响应式的UI框架

扩展 Vue 组件

使用Three.js制作酷炫无比的无穷隧道特效

一个治愈JavaScript疲劳的学习计划

全栈工程师技能大全

WEB前端性能优化常见方法

一小时内搭建一个全栈Web应用框架

干货:CSS 专业技巧

四步实现React页面过渡动画效果

让你分分钟理解 JavaScript 闭包



小手一抖,资料全有。长按二维码关注京程一灯,阅读更多技术文章和业界动态。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-10-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京程一灯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档