基于Websocket的呼叫中心应用
2017-06-01陈佳乐
陈佳乐
摘要:众所周知,传统的B/S架构在实现服务端与客户端实时通信方面,常采用客户端“拉”与服务器“推”等技术,这些技术都存在诸如实时性差、效率低等问题。该文通过将当今流行的WebSocket与传统的B/S实时通信技术进行比较,旨在说明采用WebSocket在B/S架构中实现实时通信的众多优点,并以呼叫中心为例简要阐述WebSocket在实际项目中的应用。
关键词:WebSocket;呼叫中心;应用
中图分类号:TP393 文献标识码:A 文章编号:1009-3044(2017)08-0074-04
1传统“Web实时”解决方案
由于HTTP协议为无状态的交互协议,客户端与服务端的交互通过一问一答来实现数据的传输。因此,对于需要实现实时业务的Web系统,传统的实时解决方案主要分为:客户端“拉”与服务端“推”两种方式,我们将之统称为反向Ajax技术(Reverse Ajax)。
顾名思义,这两种Web的实时解决方案都是借助于客户端周期性反复发起的Ajax请求来反向推送服务端需要推送的实时交互信息以达到实时传输的目的。下面我们就来详细分析一下这两种方案的优缺点。
1.1客户端“拉”(Client Puff)
客户端“拉”指由客户端周期性反复发起HTTP请求,将实时性数据“拉”至客户端。因此,客户端“拉”的关键在于客户端,服务端还是在被动的响应客户端的请求。这种实时性交互方案的实现方式主要分为:页面定时刷新和Ajax定时轮询两种方案。
1.1.1页面定时刷新
页面定时刷新,通俗地讲就是页面周期性加载功能,它通过HTML页面自带的定时刷新功能实现消息的“实时”获取。具体实现方式为在HTML的标签中加入实现定时刷新。
具体时序如圖1所示。
从图中我们不难看出浏览器每隔2秒发起一次刷新,每次刷新加载的都是该HTML文件以及HTML文件中所包含的全部数据与资源文件。早期我们就是通过这种浏览器机械的刷新操作达到数据的“实时”传输。这种最为原始的消息实时交互方式有其优势,如代码逻辑简单,仅仅通过HTML内置标签就可以实现定时加载,浏览器兼容性好,但也存在不足,如界面频繁闪烁,数据的频繁传输与加载加重了服务器的负担。
1.1.2 Ajax定时轮询
Ajax定时轮询的提出主要是为了解决页面定时刷新造成的页面与资源传输占用大量带宽的问题而采取的一种折中方案。Ajax(Asynchronous Javascript And XML)异步交互通信技术也称页面局部刷新技术,通过它同样可以实现数据的实时交互。
具体实现方式为:在页面中启动一个js定时器,让其周期性地发起Ajax请求,以从服务器上获取数据。当Ajax请求发起的周期时间设置得越短,实时性就越高。
优点:相对于页面定时刷新技术来说,Ajox定时轮询减少了不必要的资源传输与加载;由于是异步发起Web请求,因此对用户来说是“透明”的;页面无频繁闪烁,用户体验有所改善;浏览器兼容性好。
缺点:服务器接入压力依旧很大。试想,如果有100个用户需要获取服务器实时数据,以每2秒为一个周期发起请求,那么服务器在10秒内需要处理500个请求,负载过大。
通过以上的分析,我们不难看出,客户端“拉”实现的实时交互都是基于定时器不断轮询实现宏观上的“实时交互”,而从微观角度上分析并没有达到真正意义上的实时,并且这种实现方式会给服务端造成一定的压力,轻者存在访问延迟,重者直接造成服务端拒绝服务。因此,对于呼叫中心这种需要高效地整合电话资源并将电话线路的实时状态反应在网页上的实时性要求较高的系统,客户端“拉”的技术显然不符合要求。因为“拉”的实效性是由周期时间差所决定的,事件的随机性与周期的固定性肯定存在时间差。当一个客户呼入或挂机事件发生时,如果当前服务端没有收到客户端的周期请求,则系统将无法及时地通知到相关的坐席。
1.2服务端“推”(Server Push)
鉴于客户端“拉”的实时性不理想且会对服务器造成负载压力,客户端“拉”的方案列入备选。说起服务端“推”技术,业界也有两种不同的实现方式:一是基于Http协议的长连接,二是基于客户端第三方组件的网络套接字技术。其中第二种实现方式由于需要客户端在有安装第三方组件的情况下才可以使用,因此这种方式不作为我们本文讨论的重点。如果读者感兴趣可以自行了解aflax socket与Java applet。
本文重点讨论的服务端“推”技术是基于Http协议的长连接,它与客户端“拉”技术的共通之处在于都是基于浏览器发起的Http请求进行实时消息交互,不同之处在于该连接为长连接而非客户端“拉”技术的短连接。它的具体实现方式可分为基于Iframe流和基于Comet流的实现方式。
1.2.1Iframe流
Iframe流实现方式是指在HTML界面中插入一个隐藏的If-rame帧,将帧的数据请求(即src属性)指向一个服务端长连接数据源。当服务端有实时消息时,通过该客户端的连接回送一个基于客户端界面的JS函数调用的脚本片断来实现消息的实时显示。(如:其中show_msg函数为原先客户端网页JS中已经存在的函数)
优点:数据通道利用率高,一次连接多次推送,减少周期性轮询带来不必要的连接请求。消息实时性高,真正实现了服务端想“推”就推的功能需求。浏览器兼容性好,基本上所有浏览器均支持Iframe标签。
缺点:第一、建立的长连接数据通道是一个半双工通道,一旦连接建立后该通道只能用于服务端向客户端推送消息,如果客户端要向服务端发送请求则需要另外再建立一个通道。第二、对于错误消息与连接的异常断开,没有一个有效的调试与定位手段,给程序调试与编码带来困难。
1.2.2Comet流
Comet流也是长连接服务器“推”技术发展的成果。它的实现原理是由客户端发起一个XMLHttpRequest连接,在服务端通过AsyrwContext保持与客户端的长连接,当服务端收到一个消息事件后直接由服务端通过AsyncContext对象以流的方式发送给客户端。但由于它是基于FireFox浏览器multi-part标志所开发的一种面向流的实时消息交互技术,具有Multi-Part标志的FireFox2.0浏览器允许在XmlHttpRequest对象readystate为3时读取浏览器缓冲区中的数据,而其他浏览器并不一定都具有该特性,因此,它的一个致命的缺点就是浏览器兼容性不好。
优点:数据通道利用率高,基本上一次连接成功后,数据可以实现多次推送。消息推送实时性高。
缺点:浏览器兼容性差,不是所有的浏览器均支持Multi-Part标志。消息通道依旧只能进行半双工传输。
通过上面对服务端主流“推”技术比较,我们可以得出如下结论:服务端“推”技术虽然在实时交互上比客户端“拉”技术有所提高,但依旧存在不少问题,如浏览器兼容性差、问题定位手段有限等。如果在呼叫中心系统中采用Iframe流技术,那么在话务消息传输问题上出现异常时定位将变得比较麻烦,而采用Comet流技术又只能基于FireFox浏览器,用户体验性较差。因此,急需一项新的技术解决Web实时消息传输问题。
2当今“Web实时”解决方案
为了提高Web实时消息传输的效率,Html5标准中新增了WebSocket通信协议该协议的制定旨在解决Web即时通信问题。通过WebSocket消息协议我们可以在Web上实现双向的、有状态的消息通信,以达到真正意义上的即时消息通信,提高系统的时效性。
2.1WebSocket协议简介
HTML5规范中将WebSocket协议定义为一种可用于全双工即时性消息传输的协议,那么它与之前我们所描述的基于thtp协议的即时通信有什么区别呢?下面我们就来简单了解一下它们的区别。
我们都知道Hap协议是基于Tcp协议之上的应用层协议,它的交互方式为一次请求一次响应,因此它是无状态的协议。而WebSocket协议的连接建立需要先通过Http协议的一次握手与协议转换(Switching Protocols)才能升级为WebSocket协议,因此它也是基于Tcp协议之上的一种应用层协议。由于WebSocket经过了一次协议转换,一旦链路建立成功将一直保持着客户端与服务端的Tcp链路连接。这时无论是客户端需要传输消息给服务端,还是服务端需推送消息给客户端,都可以通过该通道进行消息交互。完美地解决了Http协议只能通过轮询或长连接才可进行的半双工实时消息传递的问题,提高了消息传输的效率。
综上所述,正因为WebSocket协议在消息交互上与Http协议完全不同,它支持全双工即时通信,再加上HTML5标准发布后不久各大浏览器厂商纷纷响应,截止目前几大主流浏览器厂商均已支持WebSocket协议。因此,如果能将WebSocket协議用于呼叫中心即时消息,将可解决Http协议即时消息传输的效率问题。
3WebSocket在呼叫中心中的应用
一般呼叫中心应用都存在如下应用场景,坐席登录呼叫中心后有客户通过电话呼入,那么系统需要向对应的坐席推送客户资料与服务记录等信息,以方便坐席更好地为客户服务。对于这样一个应用场景如果通过先前介绍的Http轮询的方式获取服务器的即时消息,那势必会造成消息延时与服务器连接压力。而采用WebSocket协议则可以提高即时消息传输的效率,服务端与每个坐席之间仅需要建立一条WebSocket通道从而减少了Http轮询带来的服务端压力。
3.1数据结构定义
客户端与服务端的消息交互需要事先约定好双方交互的数据结构。考虑到在B/S架构中浏览器对Json数据易于解析,因此,当一个客户通过电话呼入呼叫中心,服务端将生成一个NotifyObj对象,该对象保存需要通知浏览器的全部消息。对应的消息结构如下图所示:
其中各字段分别用于标识通知模块(model)、事件(ac-tion)、坐席工号(agent)、消息结构(data)。在实际使用过程中,当系统收到一个通知事件,如客户呼人事件,它将创建好Noti一fyObj对象并填充该对象的各属性值后通过Google的Gson将NotifyObj对象进行Json序列化后由WebSocket通知浏览器。
3.2客户端WebSocket实现
前端界面通过WebSocket与后台服务器进行通信,需要通过Javascript的WebSocket对象进行交互。但考虑到目前部分浏览器对WebSocket的支持度不一样,所以在WebSocket对象新建之前需对浏览器支持WebSocket的能力进行一下验证,大致流程如下图所示:
其中需要特别注意的是WebSocket的消息处理,在呼叫中心中我们通过onmessage响应由服务端传送过来的AgentNoti-fyObj对象,通过解析该对象的data结构获取呼入的客户信息,进行弹屏显示。
3.3服务端WebSocket实现
由于服务器采用SpringMVC+Hiberm#e做为服务端开发框架,因此后端的WebSocket组件自然选择Spring4.1的WebSock-ef组件。但有一点需要注意的就是Web容器的选择需要注意版本,其中Tomcat应选用7.0.27+版本,Jetty应选用7.0+版本,下面我们就服务端的WebSocket实现流程进行简单介绍.
1)通过继承Spring的TextWebSocketHandler类实现一个传输文本帧WebSocket的控制器。
2)分别实现父类TextWebSoeketHandler继承的接口,添加相应的业务逻辑。afterConneetionEstablished接口在WebSocket链路连接建立后触发,在该函数中我们将通过afterConnectio-nEstablished接口参数WebSocketSession获取由WebSocket拦截器从HttpSession存入的用户信息,将用户信息与WebSocketSes-sion建立对应关系,当后续需要向特定的用户推送消息时,可直接通过用户信息直接找到对应的WebSocketSession进行推送。handleTextMessage接口在服务端收到客户端WebSocket推送的消息时触发,该接口我们用于处理客户端与服务端之前的周期心跳報文,发送心跳的目的是为了检测WebSocket通道的保活情况,避免死连接的发生。afterConnectionClosed接口在客户端关闭WebSocket接口时触发,呼叫中心系统通过该接口对系统对象的释构释放资源并维护好aferConnectionEstablished建立的用户与WebSocketSession接口关系表。handleTransport-Error接口在服务端与客户端之间出现链路异常时触发,呼叫中心通过该接口用于处理系统资源的回收与异常日志的记录,用后期异常定位提供线索。
3)通过继承HttpSessionHandshakeInterceptor添加Web—Socket拦截器实现。
4)实现由HttpSessionHandshakeInterceptor继承的拦截器业务逻辑。beforeHatutshake接口在WebSocket协议转换时触发,通过该接口我们实现了将原先登录后存放于HttpSession中的用户信息转存于attributes对象,该对象为beforeHandshake函数的最后一个参数它就是步骤2aafterConnectionEstablished函数的WebSocketSession会话getAttributes ()获到的键值对。
5)在Spring配置文件中添加PhoneAgentController初始化配置与拦截器配置其中websocket:mapping标签定义了从浏览器js连接服务端WebSocket的具体地址,如ws://192.168.99.18:8081/callcenter/agent。具体配置文件信息如下图所示:
到此为止,服务端的WebSocket服务端的开发就已经完成了。
4结束语
本文通过将传统Http即时消息通信技术与HTML5 Web-Socket即时消息技术做对比得出在B/S架构模式下通过Web-Socket技术实现消息的即时全双工交互效率高于传统的HTTP轮询方式的消息传输。并将WebSocket技术应用于呼叫中心项目实现话务状态的实时通知,达到了预期的效果。