跨域(二)
Comet
Ajax是一种从页面向服务器请求数据的技术,而Comet则是一种服务器向页面推送数据的技术。Comet能够让信息近乎实时地被推送到页面上
有两种实现Comet的方式:长轮询和流
1、轮询
1)短轮询:浏览器定时向服务器发送请求,看有没有更新数据
2)长轮询:页面发送一个到服务器的请求,然后服务器一直保持打开状态,直到有数据可发送。发送完数据之后,浏览器关闭连接,随即又发起一个到服务器的请求
无论是短轮询还是长轮询,浏览器都要在接收数据之前,先发起浏览器向服务器的连接,轮询的优势是所有浏览器都支持,因为使用xhr对象和settimeout()就能实现。
而你要做的是决定什么时候发送请求
2、流
流不同于上述两种轮询,因为它在页面的整个生命周期内只使用一个http连接。具体来说,就是浏览器向服务器发送一个请求,而服务器保持连接打开,
然后周期性地向浏览器发送数据。
通过侦听readystatechange事件及检测readyState的值是否为3,就可以利用xhr对象实现http流
function createStreamingClient(url,progress,finished){ var xhr = new XMLHttpRequest(), received = 0; xhr.open('get',url,true); xhr.onreadystatechange = function(){ var result; if(xhr.readyState == 3){ // 只取得最新数据并调整计数器 result = xhr.responseText.substring(received); received +=result.length; //调用progress回调 progress(result) }else if(xhr.readyState == 4){ finished(xhr.responseText) } }; xhr.send(null); return xhr } var client = createStreamingClient('localhost/index.php', function(data){ console.log('Received' + data) }, function(data){ console.log('Done!'); } )
这个createStreamingClient()函数接收三个参数:要链接的url、在接收到数据时调用到函数以及关闭这个连接时调用的函数
SSE
SSE(Server-SentEvent,服务器发送事件)。SSE API用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。
服务器响应的MIME类型必须是text/event-stream,而且是浏览器中的Javascript API能解析格式输出。SSE支持短轮询、长轮询和HTTP流,
而且能在断开连接时自动确定何时重新连接。
1)SSE API
创建一个新的EventSource对象
eg
var source = new EventSource('myevets.php');
*:传入的URL必须与创建对象的页面同源。EventSource实例有一个readyState属性,值为0表示正连接到服务器,值为1表示打开了连接,值为2表示关闭了连接。
另外,还有以下三个事件
open: 在建立连接时触发。
message: 在从服务器接收到新事件时触发。
error: 在无法建立连接时触发。
source.onmessage = function(event){ var data = event.data; //处理数据 }
服务器发回的数据以字符串形式保存在event.data中。
默认情况下,EventSource对象会保持与服务器的活动连接。如果连接断开,还会重新连接。这意味着SSE适合长轮询和HTTP流。如果想强制立即断开连接并且不再
重新连接,可以调用close()方法
source.close();
Web Sockets
Web Sockets的目标是在一个单独的持久连接上提供全双工、双向通信。标准的http服务器无法实现web sockes。只有支持这种协议的专门服务器才能正常工作。
由于Web Sockets使用了自定义的协议,所以url模式也略有不同。未加密的连接不再是http://,而是ws://;加密的连接也不是https://,而是wss://。SSE
使用自定义协议的好处是,能够在客户端和服务器之间发送非常少量的数据,而不必担心http那样字节级的开销。
1)Web Sockets API
//创建一个Web Sockets实例 var socket = new WebSocket('ws://www.example.com/server.php');
*:必须给WebSocket构造函数传入绝对url。同源策略对Web Sockets不适用,因此可以通过它打开到人和站点到连接。
与xhr类似,WebSocket也有一个表示当前状态到readyState属性。不过,与xhr并不相同。
WebSocket.OPENING(0):正在建立连接。 WebSocket.OPEN(1):已经建立连接。 WebSocket.CLOSING(2):正在关闭连接。 WebSocket.CLOSE(3):已经关闭连接。
WebSocket没有readystatechange事件;不过,它有其他事件,对应不同到状态。readyState到值永远从0开始。
要关闭Web Socket,可以在任何时候调用close()方法
socket.close();
调用colse()之后,readyState的值立即变为2(正在关闭),而在关闭连接后就会变成3.
2)发送和接收数据
var socket = new WebSocket('ws://www.example.com/server.php'); socket.send('Hello world');
因为Web Sockets只能通过连接发送纯文本数据,对于复杂的数据结构,在通过连接发送之前,必须进行序列化
var message = { time: new Date(), text: 'Hello world!', clientId:'9527' }; socket.send(JSON.stringify(message));
当服务器向客户端发来消息时,WebSocket对象就会触发message事件。返回数据保存在event.data属性中
socket.onmessage = function(event){ var data = event.data; //处理数据 }
3)其他事件
open:在成功建立连接时触发
error:在发生错误时触发。连接不能持续。
close:在连接关闭时触发
var socket = new WebSocket('ws://www.example.com/server.php'); socket.onopen = function(){ alert('connection established.'); } socket.onerror = function(){ alert('connection error.'); } socket.onclose = function(){ alert('connection closed.'); }
在这三个事件中,只有close事件的event对象you额外的信息。这个事件的事件对象you是三个额外的属性:
wasClean:是一个布尔值,表示连接是否已经明确地关闭;
code:服务器返回的数值状态码;
reason:一个字符串,包含服务器发回的消息
socket.onclose = function(event){ console.log('Was clean?' + event.wasClean + ' code=' + event.code + ' reason=' + event.reason); }
使用sse还是web Sockets
1、是否有自由度建立和维护web sockets服务器?
WebSocket协议不同于http,所有现有浏览器不能用于web socket,sse倒是通过常规的http通信,因此现有浏览器都满足需求
2、到底需不需要双向通信
如果只需读取服务器数据,如比赛成绩,那么sse比较容易实现。如果必须双向通信,比如聊天室,那么web sockets显然更好
在不能使用web sockets的情况下,组合xhr和sse也能实现双向通信的