http长连接总结

来源:互联网 发布:酒店网络应用 编辑:程序博客网 时间:2024/06/05 16:30

序言

经常有业务需要在两个web客户端进行通信,比如,移动端两人对战游戏,针对此类场景最常使用的技术便是普通的ajax,两个客户端不断发ajax请求到服务端询问另外一方的信息,然后进行处理。如果回到多年前的聊天室场景,那就是N个客户端需要进行通讯了。本篇主要总结目前主流的几种实现此类需求的技术方案。

ajax短轮询

为了不断更新页面上的某些信息,相信大部分人都使用过最普通的ajax请求,而且是定时请求(也叫polling),该种方案实现起来最简单粗暴,当然,效率会比较差,因为后台信息可能一直没有更新,做了无用功。不过此方法有个好处就是跨域请求比较简单,只需要服务器返回
‘Access-Control-Allow-Origin’:’*’ 这个响应头,浏览器便认为此跨域请求是安全的(IE得使用XDomainRequest)。
请求示意图如下,一次请求一次返回。

这里写图片描述

ajax长连接

ajax短轮询模型中,每一次请求,不管有没有新的数据,服务端都会返回,然后中断此次连接,这就会造成很多的连接都在做无用功,所以又出现了所谓的长连接,也叫long-polling。

这里写图片描述

跟polling不同的是,在一次请求过程中,如果服务端发现没有数据,服务端不会立即返回结果,而是hold住这个请求,等到有数据或者是超时了,再返回结果。这样可以减少很多无用功的请求。 当客户端返回一次请求后,会重新发起下次请求,周而复始。此种方案的跨域跟polling是一样的。

ajax streaming

在使用ajax的时候,经常有如下的代码片段,

xhr.onreadystatechange=function(){    if(xhr.readyState==4){        // do business    }};

我们一般会在XMLHttpRequest对象的readyState=4时去处理数据,因为这个时候,我们已经可以拿到请求的整体结果了,殊不知,其实,部分浏览器还支持所谓的ajax流式处理,即使数据只传递了一部分,也是可以提前处理的,ajax streaming的处理模式为:

xhr.onreadystatechange=function(){    if(xhr.readyState==3){        // do business    }else if(xhr.readyState==4){        // do business    }};

其实就是在readyState=3的时候,提前读取请求的结果,这样就像水管一样,可以逐步处理请求,鉴于某E的问题,需要进行兼容处理。模型示意图如下:

这里写图片描述

基于iframe流

iframe大家都用过,当然,更多的是指向一个普通的文档,比如一个html文档或者是jsp文件。其实,iframe也可以指向一个后端的接口,然后后端可以源源不断输出数据到客户端,注意,由于iframe获取到数据后会进行标准的解析,所以通常要返回 <script>callback(data)</script> 这种格式的脚本内容,它跟 ajax streaming相似,不过这种方式跨域不了,所以要依场景使用。模式如下:

这里写图片描述

基于htmlfile

使用上面的iframe流有一个不好的地方就是在IE中,由于iframe请求没有回来,所以会看到浏览器处于加载的状态,体验很不好。为了解决这个问题,出现了一种称为htmlfile的解决方案,其本质上还是使用iframe流。代码示意如下:

var doc = new ActiveXObject("htmlfile");doc.open();doc.write("<!DOCTYPE html><html><body><script  type=\"text/javascript\">" +"document.domain='" + document.domain + "';" +"<\/script><\/body><\/html>");doc.close();var content = doc.createElement("div");doc.body.appendChild(content);content.innerHTML = "<iframe src='" + url + "'><\/iframe>";

不过IE8实践发现,IE中是最终一起执行的,而没有逐步处理,这个还需要进一步验证。

script动态脚本

我们经常会动态创建一些script标签(jsonp),它的好处是可以动态加载js,在这里,也可以让其指向一个后台的数据接口,如果后台没有数据,可以hold住这个请求,当有数据时再返回。前端可以监听onload事件,一旦返回了数据,请求结束,这时可以再创建一个新的请求继续处理,跟long-polling非常相似。这种方案好处在于兼容性好,而且天然支持跨域。只不过后端返回的数据内容也是
<script>callback(data)</script>这种脚本格式。模式示意如下:

这里写图片描述

websocket

websocket是html5中的一个新的技术方案,用于解决http请求无法达到全双工链路的问题。websocket利用http请求进行握手,当服务器允许并支持使用websocket的时候,浏览器和服务器会重用http底层的tcp链接,然后使用websocket独有的数据帧进行交互。
websocket提供了一套非常简洁的api,如下所示:

var ws=new WebSocket("ws://domain/path/api");ws.onopen=function(){    ws.send("input data");};ws.onmessage=function(msg){    console.log(msg);};ws.onclose=function(e){    console.log("已断开与服务器的连接");    ws.close();}

在前端可以直接创建一个WebSocket实例,然后只要监听好几个事件,就可以传递和处理数据了,非常的方便,而且没有跨域的问题。如果是在移动端,WebSocket的兼容性会更好,推荐使用。

总结

由于http的无状态性,为了更加高效的实现客户端与服务端的数据通信,方案很多,考虑到兼容性问题,前端一般使用socketio.js ,后端使用 socketio-netty 可以减少一些工作量,后续篇幅再介绍。