在web端开发遇到监控、聊天、消息提示等场景的时候,通常会有需要服务器主动推送消息给前端,前端根据相关的信息变更页面显示的效果等。一般常用的有三种模式,分别是定时请求、消息请求监听(我自己定义的名称)、websocket。
定时请求和消息请求监听其实本质上都是使用http(s)请求。
定时请求的话一般都是页面上设置setInterval或者setTimeout两种再加上一个定时的时间,在固定时间去请求后端,就相当于定时轮询。
setInterval和setTimeout这两种方式对于后端技术的的要求低,不需要后端另外搭建服务或者其他的消息机制,只需要不断地去重复调用现有的接口。但是缺点也很明显,实时性过低,在不考虑请求传输和后端反应时间的情况下,设置的时间就是最大的数据延迟时间,如果将这个时间设置很短的话,短时间内,后端和前端都需要较多的请求数据,那对于前端和后端的压力也是很大。
同时因为传输的网络状况、后端的反应时间等实际情况永远不可能为0、后端的并发,前端数据的处理等一系列的情况都需要去考虑到。在使用setInterval且配置时间过短的情况下,经常会出现前一个请求还没返回,后一个的请求都已经返回了,就会页面上处理的数据并非按照实际的时间进行处理展示的情况。此时使用setTimeout的话,虽然解决了请求顺序的问题,但是遇到请求时间较长的情况,实时性还是有延迟,延迟时间大概就是设置的timeout时间加上http(s)请求的时间,对于后端相应返回的时间的要求比较高。
另外,在使用这种方式的时候,前端的开发人员一定要在页面销毁的时候去取消掉设置的定时或者请求,否则定时请求会一直保留。
消息请求监听的话比较适用于服务器单向通知前端,实质上跟第一种是一样的道理,不同的地方是,它这种方式是直接与后端建立一个请求,后端会将这个请求保持住,一旦有数据的时候,后端会将相关的数据通过这个请求返回给前端,前端在得到返回后会去处理数据并且再次重新建立一个消息请求,重新开始这个循环。
考虑到请求超时等配置,一般这个请求都是会在一定时间返回,让前端结束这次的消息监听,重新开始一个新的消息监听。
在实际情况中经常会出现在后端返回数据前端还没有处理完并建立新的消息监听请求时有新消息的情况,如果处理不好这种情况就容易出现消息丢失,或者消息和页面对不上的情况,这种情况的解决方案是消息打包,后端将比如一段时间内的消息打个包,在满足的时候再返回。
在此方式过程中,如果传输的数据包的时候,如果数据包过大,会造成连接请求的时间过长,影响监听的实时性,便可以考虑在消息打包的时候,生成一个类似于id之类的唯一编码,在消息监听返回的时候直接将这个编码抛给前端,前端接到编码后,立即重新建立一个新的消息监听,同时通过一个新的接口用监听返回的编码去向后端请求相关的数据,这样的话,消息监听的服务和消息返回的服务可以分开来,消息提示和消息内容相互独立,不光解决了数据接收的实时性,同时对于前端需要提示(类似于某个地方出现小红点之类的),但是不要立刻知道需要提示内容等情况的话可能效果更好。
建议在后端能力满足的情况下,使用这套方案。从实践而言,这套方案的话,哪怕去后端去拿数据,返回也很快的,因为不同于定时请求请求,主要的还是从消息存储中去拿,返回的速度完全是架构的问题,再加上这套方案的实时性很好,故此推荐。
使用此方式的情况下,如果前端需要与后端进行数据交换,可以直接使用正常的http(s)请求即可。
websocket的话,似乎是最佳解决方案,但是相比较而言,它在某些方面优先不足,比如浏览器版本(当然,现在这个几乎可以忽略不计)、浏览器是否禁用JavaScript、token认证、服务器、多端兼容等方面的问题。当然,以上这些问题在很多小的,或者要求不是那么高的项目中基本不用考虑,只要不考虑这些问题,websocket几乎就是最优的方案:实时性很好,消息容量也能满足几乎所有的场景……反正几乎都是优点,只是在一些很古老的项目,例如还需要兼容ie的(不知道这些项目还留着干嘛),确实需要还是要考虑兼容的,一般用户谁没事去禁用JavaScript,token啥的换一套检验方式就得了,服务器啥的,也不是啥问题,现在一套websocket服务,很轻的。
以上就是一般常用的三种方式,但从技术上而言,第一种最简单。如果不考虑技术的话,建议优先websocket,消息请求监听,最后才是定时请求。