最近使用了两种不同的方式来实现即时通信:一种是基于timer的轮询(与项目内后端协作),一种是基于websocket的双向通信(项目与第三方集成和协作)。接下来,我们将介绍这两种不同的即时通讯方式的基本用法和优缺点。第一种:Ajax轮询轮询需求场景:显示的面板数据需要实时刷新。实现过程:客户端主动向服务端发送请求,等待一段固定的时间(通常使用JavaScript的setInterval函数),然后再次发送请求setInterval(function(){fetch('get-csrf').then((res)=>res.json()).then((res)=>{console.log(res);});},5*1000);优点:实现简单,不需要特定的服务端功能,客户端即可处理。并且所有浏览器都支持,良好的错误处理系统,超时管理缺点:浪费服务器和网络资源:大部分链接无效,重复响应数据有延迟:setInterval的时间间隔设置的越长,新数据上server到达客户端的时间越长,非可伸缩响应的结果没有顺序:因为是异步请求,当发送的请求没有返回结果时,会再次发送后续的请求,而在这个时候如果后面的请求返回结果早于前面的请求,那么前面的请求返回结果数据的时候,就已经过时无效了。场景:每隔5s定时请求接口vs接口返回,然后每隔5s获取请求响应,然后每隔5s执行一次。可以保证响应的顺序,但同时需要考虑到当请求没有响应时,后面的操作将不会执行。可以增加超时响应的处理,如果超过一定时间没有响应则取消请求。超时时间还要考虑到其他需要时间过长的界面,没有实时刷新功能防止取消超时后没有数据显示。实现fetch请求超时取消请求的方式可以通过timeout+abort方法实现。Promise.race([fetch(),timout])方法也可以实现超时功能//接口返回后,每隔5s获取该功能。getToken(){fetch('get-csrf').then((res)=>res.json()).then((res)=>{console.log(res);setTimeout(()=>{getToken();},5*1000);});}getToken();longPolling实现过程:客户端向服务端发送请求接口,然后等待服务端响应。服务器端需要实现一个特定的功能来允许请求被挂起。只要有事件发生,服务器端就会在挂起的请求中发送响应并关闭请求。客户端将使用此响应并打开一个新响应。服务器端长期存在的Ajax请求。与上面提到的客户端主动轮询的方式相比,服务端需要有一个特殊的功能来临时挂起连接。在项目实现过程中,对于前端人员,采用第一种方式,实现速度更快,可操作性更高客户端代码示例:functiongetToken(){ fetch('get-csrf').then((res)=>res.json()).then((res)=>{console.log(res);});}getToken();/**这种长轮询方式下,客户端在XMLHttpRequest就绪状态时4(即数据传输结束),调用回调函数处理信息。当readystate为4时,数据传输结束,连接已经关闭**/其他轮询方式script标签&IframeStream的长轮询:实现方式:在页面上附加script标签,让脚本执行。服务器端会挂起连接,直到有事件发生,然后将脚本内容发回给浏览器,然后重新打开另一个脚本标签来获取下一个事件。(script标签的src或者iframe的src指向服务器地址)没有办法实现可靠的错误处理或者跟踪连接状态,并且具有跨域功能,实现方式更多比如cors第二种:websocketfirst这种轮询的方式是基于HTTP方式实现的。HTTP连接是被动的(需要一端主动发起)、无状态的、单向的、非持久的。同时轮询实现的数据延迟(时间间隔)和重复请求的浪费是缺点。对于项目场景如:频繁请求更新数据:当控制台操作2D地图时,需要立即将地图视野的变化(平移、缩放、旋转等)传输到第三方的3D地图-方综合应用,同步响应。操作实时性要求高,响应频繁。多用户通信,由于集成网页的方式,通过chromium加载不同的页面,这些页面相当于独立的浏览器页面,各个页面之间通信,页面与第三方集成应用之间也需要通信,所以综合考虑websocket的双向实时通信能力更能满足业务选择。websocket与WebSocket的连接首先进行TCP的三次握手,然后依赖HTTP协议进行一次握手。握手成功后,直接从TCP通道传输数据,与HTTP无关。客户端:当客户端连接到服务器时,会向服务器发送类似下面的http报文,升级协议GETws://localhost:8080/socket.io/?UserGroup=toyGroup&EIO=3&transport=websocketHTTP/1.1Host:http://localhost:8080Connection:UpgradeUpgrade:websocketOrigin:http://localhost:8000Sec-WebSocket-Version:13Sec-WebSocket-Key:V1yj21hlXCrSK2HDuJsD9A==Sec-WebSocket-Extensions:permessage-deflate;client_max_window_bitsConnection表示:Upgr升级协议Upgrade:websocket:其作用是告诉服务端需要将通信协议切换为websocketSec-WebSocket-Version:13:表示websocket的版本。如果服务器不支持该版本,则需要返回一个Sec-WebSocket-Version头,其中包含服务器支持的版本号。Sec-WebSocket-Key:与服务器后面响应头中的Sec-WebSocket-Accept匹配,提供基本的保护,如恶意连接或无意连接。服务器:如果服务器支持websocket协议,则将通信协议切换为websocket,并向客户端发送类似如下的响应头HTTP/1.1101SwitchingProtocolsDate:Mon,20Dec202107:14:21GMTConnection:upgradeUpgrade:websocketSec-WebSocket-Accept:8L5tW9vVu5z9vfRMglkhare9o58=返回状态码为101,表示客户端同意协议转换请求,并转换为websocket协议。Sec-WebSocket-Accept是根据客户端请求头的Sec-WebSocket-Key计算出来的。websocket是使用服务端实现的:在nodejs中,使用ws模块实现constWebSocket=require('ws');constwss=newWebSocket.Server({port:8080});wss.on('connection',functionconnection(ws){console.log('Serverconnection');ws.on('message',function(message){//msessage默认为Bufferconsole.log('Serverreceives:',message.toString());});ws.send('world',{binary:false});});客户端初始化websocket实例importReact,{useState,useEffect}from'react';importstylesfrom'./index.less';interfaceSocketDemoProps{}constSocketDemo:React.FC
