分类: 云计算
2022-08-23 14:04:43
web端的IM应用,由于浏览器的兼容性以及其固有的“客户端请求服务器处理并响应”的通信模型,造成了要在浏览器中实现一个兼容性较好的IM应用,其通信过程必然是诸多技术的组合,本文的目的就是要详细探讨这些技术并分析其原理和过程。
传统Web的通信原理
浏览器本身作为一个瘦客户端,不具备直接通过系统调用来达到和处于异地的另外一个客户端浏览器通信的功能。这和我们桌面应用的工作方式是不同的,通常桌面应用通过socket可以和远程主机上另外一端的一个进程建立TCP连接,从而达到全双工的即时通信。
浏览器从诞生开始一直走的是客户端请求服务器,服务器返回结果的模式,即使发展至今仍然没有任何改变。所以可以肯定的是,要想实现两个客户端的通信,必然要通过服务器进行信息的转发。例如A要和B通信,则应该是A先把信息发送给IM应用服务器,服务器根据A信息中携带的接收者将它再转发给B,同样B到A也是这种模式。
传统通信方式实现IM应用需要解决的问题
我们认识到基于web实现IM软件依然要走浏览器请求服务器的模式,这这种方式下,针对IM软件的开发需要解决如下三个问题:
双全工通信:
即达到浏览器拉取(pull)服务器数据,服务器推送(push)数据到浏览器;
低延迟:
即浏览器A发送给B的信息经过服务器要快速转发给B,同理B的信息也要快速交给A,实际上就是要求任何浏览器能够快速请求服务器的数据,服务器能够快速推送数据到浏览器;
支持跨域:
通常客户端浏览器和服务器都是处于网络的不同位置,浏览器本身不允许通过脚本直接访问不同域名下的服务器,即使IP地址相同域名不同也不行,域名相同端口不同也不行,这方面主要是为了安全考虑。
即时通讯网注:关于浏览器跨域访问导致的安全问题,有一个被称为CSRF网络攻击方式,请看下面的摘录
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。
CSRF这种攻击方式在2000年已经被国外的安全人员提出,但在国内,直到06年才开始被关注,08年,国内外的多个大型社区和交互网站分别爆出CSRF漏洞,如:NYTimes.com(纽约时报)、Metafilter(一个大型的BLOG网站),YouTube和百度HI......而现在,互联网上的许多站点仍对此毫无防备,以至于安全业界称CSRF为“沉睡的巨人”。
全双工低延迟的解决办法
这是最简单的一种解决方案,其原理是在客户端通过Ajax的方式的方式每隔一小段时间就发送一个请求到服务器,服务器返回最新数据,然后客户端根据获得的数据来更新界面,这样就间接实现了即时通信。优点是简单,缺点是对服务器压力较大,浪费带宽流量(通常情况下数据都是没有发生改变的)。
长轮询(long-polling)
在上面的轮询解决方案中,由于每次都要发送一个请求,服务端不管数据是否发生变化都发送数据,请求完成后连接关闭。这中间经过的很多通信是不必要的,于是又出现了长轮询(long-polling)方式。这种方式是客户端发送一个请求到服务器,服务器查看客户端请求的数据是否发生了变化(是否有最新数据),如果发生变化则立即响应返回,否则保持这个连接并定期检查最新数据,直到发生了数据更新或连接超时。同时客户端连接一旦断开,则再次发出请求,这样在相同时间内大大减少了客户端请求服务器的次数。即时通讯聊天软件app开发可以加蔚可云的v:weikeyun24咨询
基于http-stream通信
上面的long-polling技术为了保持客户端与服务端的长连接采取的是服务端阻塞(保持响应不返回),客户端轮询的方式,在Comet技术中,还存在一种基于http-stream流的通信方式。其原理是让客户端在一次请求中保持和服务端连接不断开,然后服务端源源不断传送数据给客户端,就好比数据流一样,并不是一次性将数据全部发给客户端。它与polling方式的区别在于整个通信过程客户端只发送一次请求,然后服务端保持与客户端的长连接,并利用这个连接在回送数据给客户端。
这种方案有分为几种不同的数据流传输方式。
SSE(服务器推送事件(Server-sent Events)
为了解决浏览器只能够单向传输数据到服务端,HTML5提供了一种新的技术叫做服务器推送事件SSE(关于该技术详细介绍请参见《SSE技术详解:一种全新的HTML5服务器推送事件技术》),它能够实现客户端请求服务端,然后服务端利用与客户端建立的这条通信连接push数据给客户端,客户端接收数据并处理的目的。从独立的角度看,SSE技术提供的是从服务器单向推送数据给浏览器的功能,但是配合浏览器主动请求,实际上就实现了客户端和服务器的双向通信。它的原理是在客户端构造一个eventSource对象,该对象具有readySate属性,分别表示如下:
0:正在连接到服务器;
1:打开了连接;
2:关闭了连接。
同时eventSource对象会保持与服务器的长连接,断开后会自动重连,如果要强制连接可以调用它的close方法。可以它的监听onmessage事件,服务端遵循SSE数据传输的格式给客户端,客户端在onmessage事件触发时就能够接收到数据,从而进行某种处理。
跨域解决办法
关于跨域是什么,限于篇幅所限,这里不做介绍,网上有很多详细的文章,这里只列举解决办法。
基于XHR的COSR(跨域资源共享)
CORS(跨域资源共享)是一种允许浏览器脚本向出于不同域名下服务器发送请求的技术,它是在原生XHR请求的基础上,XHR调用open方法时,地址指向一个跨域的地址,在服务端通过设置'Access-Control-Allow-Origin':'*'响应头部告诉浏览器,发送的数据是一个来自于跨域的并且服务器允许响应的数据,浏览器接收到这个header之后就会绕过平常的跨域限制,从而和平时的XHR通信没有区别。该方法的主要好处是在于客户端代码不用修改,服务端只需要添加'Access-Control-Allow-Origin':'*'头部即可。适用于ff,safari,opera,chrome等非IE浏览器。跨域的XHR相比非跨域的XHR有一些限制,这是为了安全所需要的,主要有以下限制:
客户端不能使用setRequestHeader设置自定义头部;
不能发送和接收cookie;
调用getAllResponseHeaders()方法总会返回空字符串。
以上这些措施都是为了安全考虑,防止常见的跨站点脚本攻击(XSS)和跨站点请求伪造(CSRF)。
基于XDR的CORS
对于IE8-10,它是不支持使用原生的XHR对象请求跨域服务器的,它自己实现了一个XDomainRequest对象,类似于XHR对象,能够发送跨域请求,它主要有以下限制:
cookie不会随请求发送,也不会随响应返回;
只能设置请求头部信息中的Content-Type字段;
不能访问响应头部信息;
只支持Get和Post请求;
只支持IE8-IE10。
基于JSONP的跨域
这种方式不需要在服务端添加Access-Control-Allow-Origin头信息,其原理是利用HTML页面上script标签对跨域没有限制的特点,让它的src属性指向服务端请求的地址,其实是通过script标签发送了一个http请求,服务器接收到这个请求之后,返回的数据是自己的数据加上对客户端JS函数的调用,其原理类似于我们上面所说的iframe流的方式,客户端浏览器接收到返回的脚本调用会解析执行,从而达到更新界面的目的。
WebSocket
在上面的这些解决方案中,都是利用浏览器单向请求服务器或者服务器单向推送数据到浏览器这些技术组合在一起而形成的hack技术,在HTML5中,为了加强web的功能,提供了websocket技术,它不仅是一种web通信方式,也是一种应用层协议。它提供了浏览器和服务器之间原生的双全工跨域通信,通过浏览器和服务器之间建立websocket连接(实际上是TCP连接),在同一时刻能够实现客户端到服务器和服务器到客户端的数据发送。关于该技术的原理,在看代码之前,需要先了解websocket整个工作过程。
首先是客户端new 一个websocket对象,该对象会发送一个http请求到服务端,服务端发现这是个webscoket请求,会同意协议转换,发送回客户端一个101状态码的response,以上过程称之为一次握手,经过这次握手之后,客户端就和服务端建立了一条TCP连接,在该连接上,服务端和客户端就可以进行双向通信了。这时的双向通信在应用层走的就是ws或者wss协议了,和http就没有关系了。所谓的ws协议,就是要求客户端和服务端遵循某种格式发送数据报文(帧),然后对方才能够理解。