Ajax、服务器推和双向通信
本文由大丰哥参考自:
congdepeng博文http://congdepeng.iteye.com/blog/1169481、
stackoverflow问题“What are Long-Polling,Websockets,Server-Sent Events (SSE) and Comet?”Steve Chambers的答案
gemantic博文http://gemantic.iteye.com/blog/1553385
李刚《疯狂HTML5/CSS3/Javascript讲义》第18章
MOZILLA DEVELOPER NETWORK文档https://developer.mozilla.org/en-US/docs/Server-sent_events/Using_server-sent_events
小胡子哥博文http://www.cnblogs.com/hustskyking/p/3479336.html
感谢以上诸位前辈。
#什么是Ajax?
异步的JavaScript和XML(AsynchronousJavaScript and XML)。浏览器允许JavaScript脚本向服务器发送一个HTTP请求而又无需重新加载页面。
这个功能主要由浏览器完成,浏览器提供这个功能给JavaScript脚本来调用,然后浏览器根据规则来回调脚本去处理响应。所以Ajax中其实浏览器是最大苦力。JavaScript可以换成其他脚本,交换数据也不一定是XML格式的,所以XML也是可有可无的。所以Ajax中除了A(Asynchronous)以外,其他几个字母都是浮云。
#浏览器是如何封装异步调用功能给JavaScript调用?
浏览器把这个功能封装在一个JavaScript对象 window.XMLHttpRequest 里面。这个对象就像一个代理,为JavaScript调用提供接口。
XMLHttpRequest提供了一些方法以及属性如下:
浏览器其实只是封装了一个Socket调用而已。XMLHttpRequest作为封装这个Socket的Proxy。
Socket的工作流程:
创建Socket对象-->
建立连接-->
发送数据-->
接受数据-->
处理接受到的数据-->
关闭连接
Ajax的工作流程: 创建XMLHttpRequest对象-->设置连接的相关参数open(method,async)-->发送数据send([string])-->处理接受到的数据onreadystatechange( )
var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { // xmlhttp.readyState // xmlhttp.status } xmlhttp.open("GET","/ajax/demo_get.php",true); xmlhttp.send();
Ajax做轮询:
var xhr = new XMLHttpRequest(),type = type || "GET",data = data || null; xhr.onreadystatechange = function() { if (xhr.readyState == 4) { receive(xhr.responseText); xhr.onreadystatechange = null; } }; xhr.open(type,url,true); //IE的ActiveXObject("Microsoft.XMLHTTP")支持GET方法发送数据, //其它浏览器不支持,已测试验证 xhr.send(type == "GET" ? null: data); }; var timer = setInterval(function() { polling(); },1000); Ajax发送的内容仍然是基于HTTP协议的请求。理论上Ajax发送一个请求和你在地址栏里面输入请求是一模一样的。服务器应该根本就不知道什么是Ajax,服务器只处理HTTP请求。
#什么是Reverse Ajax 先谈谈为什么要Reverse Ajax: 因为HTTP协议是无状态的,即请求完数据后就关闭了连接。如果服务器有新的数据,浏览器是无法知道的,必须主动去查询才能知道。又因为Ajax是基于HTTP的,所以Ajax请求在缺省情况下也是无状态的,且只能从客户端向服务器端发出请求。(可以通过使用技术模拟服务器端和客户端之间的响应式通信来绕过这一限制)。
为了尽快地获得服务器端事件,我们只能使用粗暴的HTTP轮询来完成任务。轮询的间隔(两次请求相隔的时间)必须尽可能地小。
用firebug 调试一下 weibo.com 的网络请求可以发现,微博用的是轮询来实现消息提醒的,应该是用set timer隔个0.7分钟去服务器进行查询。和即时通信的web应用不同,微博提醒实时性要求不高,所以用轮询方式比较合理,没有必要用长连接。
有一个叫捎带轮询(piggyback polling)的实现方式是一种比轮询更加聪明的做法。它会删除掉所有非必需的请求(没有返回数据的请求)。不存在时间间隔,客户端在需要的时候向服务器端发送请求。不同之处在于响应的那部分上,响应被分成两个部分:对请求数据的响应和对服务器事件的响应,如果任何一部分有发生的话,在实现piggyback技术时,通常针对服务器端的所有Ajax请求可能会返回一个混合的响应。
我们回到原点,为什么要关闭连接然后再不停的建立连接呢? 为什么不建立一个时间非常长的连接呢?
因为以前的HTTP 1.0不支持长连接,所以我们不得已只能轮询!到了HTTP 1.1开始支持长连接,我们可以建立一个长连接来完成这个目的。下面介绍长连接。
#Comet Comet 是一种Web应用程序架构。可以说,它不是一种技术,而是一种思想,只是这种思想采用了已有的技术去实现。在这种思想里,客户端(Client)不需要显式地向服务器端(Server)发出请求,Server会在其数据发生变化的时候主动将数据异步发送给Client,从而使Client能够及时更新数据并呈现给用户。它不同于传统的Web,也不同于当前流行的Ajax,这种思想非常架构思想非常适合event-driven(事件驱动)式的Web应用和对交互性及实时性要求很强的应用,比如股票交易,聊天室,Web IM,网游等。
最常见的有下面两种方式: 1. HTTP 长轮询( HTTP Long Polling ) : Javascript 在处理完服务器返回的信息后再次发出请求,重新建立连接。不同于一般的 Ajax , Javascript 请求 Server ,无数据时 Server 不中断请求( still loading) ,在一定时间内获取到数据后,返回请求,又在 获取数据后再次发出请求,由此轮询。需要注意的是请求的间隔时间以及每次请求的最长 Loading 时间。做个比喻, 如果 轮询 是排队买东西,那么长轮询就是排队上厕所。买东西的话,丢下钱就可以拿东西走了,但是上厕所就不一样,有些人说不定便秘半个小时都出不来。如果只用轮询去做Web通信,那服务器就鸭梨山大了,它需要一直做接受和断开HTTP请求的操作。就像卖热销产品的店员就没有公共厕所管理员那么轻松。
ajax实现长轮询时,就是在xhr对象关闭连接的时候马上又给接上: var longPoll = function(type,url) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { // 状态为 4,数据传输完毕,重新连接 if (xhr.readyState == 4) { receive(xhr.responseText); xhr.onreadystatechange = null; //递归 longPoll(type,url); } }; xhr.open(type,true); xhr.send(); } 只要服务器断开连接,客户端马上连接,不让有一刻的休息时间,这就是长轮询。
#HTML5Server-Sent Events
Server-Sent Events
是一个从服务器到浏览器的单向推送,
实际上是将Comet技术进行了标准化。Server-Sent Events规范“定义了API来打开一个HTTP连接,通过该连接能够获取从服务器推送的通知”。
Server-Sent Events
包含新的 Javascript 对象EventSource 和新的 MIME 类型 text/event-stream,这个 MIME 类型定义了事件框架格式。
Server-Sent Events是基于HTTP streaming的。如上所述,响应会一直打开,当服务器端有事件发生的时候,事件会被写入响应中。 #HTML5 WebSocket WebSocket 启用了双向的全双工通信信道,许多浏览器(Firefox、Google Chrome 和 Safari)都已对此做了支持。连接会保持在活动状态,可以使用 JavaScript 来写入和接收数据,就像是在使用一个原始的TCP套接口一样。WebSocket URL的起始输入是ws://或是wss://(在SSL上),从这个ws和wss上可以想到,WebSocket已经不是建立在HTTP协议之上了!
var ws = new WebSocket("ws://www.example.com:8888"); ws.onopen = function(evt) {}; ws.onmessage = function(evt) { deal(evt.data); }; ws.onclose = function(evt) {}; //ws.close(); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |