JavaScript高级程序设计笔记(15)-Ajax与Comet

XHR用法

检测XHR对象的readyState属性,该属性表示请求/响应过程的当前活动阶段。属性可取值如下:

  • 0:未初始化,尚未调用open()方法
  • 1:启动,已经调用open()方法,但尚未调用send()方法
  • 2:发送,已经调用send()方法,但尚未接到响应
  • 3:接收,已经接收到部分数据
  • 4:完成,已经接收到全部响应数据,而且已经可以在客户端使用了。
    只要readyState属性的值由一个值变成另一个值,都会触发一次readystatechange事件。必须在调用open()方法之前指定onreadystatechange事件处理程序才能确保跨浏览器兼容性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function createXHR(){
if(typeof XMLHttpRequest !='undefined'){
return new XMLHttpRequest();
}else if(typeof ActiveObject !='undefined'){
var versions = ['MSXML2.XMLHttp.6.0','MSXML2.XMLHttp.3.0',
'MSXML2.XMLHttp'],
i, len;
for(i=0, len=versions.length; i< len; i++){
try{
new ActiveObject(versions[i]);
aregments.callee.activeXString = versions[i];
}catch(ex){
.....
}
}
}
}

var xhr = createXHR();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status >= 200 && xhr.status < 300||xhr.status == 304){
alert(xhr.responseText);
}else{
alert('request was unsuccessful: ' + xhr.status);
}
}
}

xhr.open('get', 'example.txt'. true);
xhr.send(null);

在接收到响应之前可以调用abort()方法来取消异步请求。

跨域资源共享(CORS: cross-origin resource sharing)

IE对CORS实现-XDR(XDomainRequest)

  • cookie不会随请求发送,也不会随响应返回
  • 只能设置请求头部信息中的Content-Type字段
  • 不能访问响应头部信息
  • 只支持 GET和POST请求

所有的XDR请求都是异步的,不能用来创建同步请求。

1
2
3
4
5
6
var xdr = new XDomainRequest();
xdr.onload = function(){
alert(xdr.responseText);
}
xdr.open('GET', 'http://www.somewhere-elese.com/page');
xdr.send(null);

其他浏览器对CORS的实现

WebKit通过XMLHttpRequest对象实现了对CORS的原生支持。

  • 不能使用setRequestHeaders()设置自定义头部
  • 不能发送和接收cookie
  • 调用getAllResponseHeaders()方法总会返回空字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
var xhr = createXHR();
xhr.onreadystatechange = functon(){
if(xhr.readyState == 4){
if(xhr.status >= 200 && xhr.status <300||xhr.status == 304){
alert(xhr.responseText);
}else{
alert('request was unsuccessful: ' + xhr.status);
}
}
}

xdr.open('GET', 'http://www.somewhere-elese.com/page');
xdr.send(null);

其他跨域技术

图片Ping

1
2
3
4
5
6
var img = new Image();
img.onload = img.onerror = function(){
alert("Done!");
}
img.src='http://www.example.com/test?name="test"';

缺点:

  • 只能发送get 请求
  • 无法访问服务的响应文本

JSONP(JSON with padding,填充式JSON或参数式JSON)

1
2
3
4
5
6
7
8
function handleResponse(response){
alert("You're at IP address " + response.ip);
}

var script = document.createElement('script');
script.src='http://freegeoip.net/json/?callback=handleResponse';
document.body.insertBefore(script, document.body,firstChild);

优点:能够直接访问响应文本,支持在浏览器与服务器之间双向通信。
缺点:

  • JSONP是从其他域中加载代码执行,如果其他域不安全,很可能会在响应中夹带一些恶意代码
  • 要确定JSONP请求是否失败并不容易

Comet

Ajax是一种从页面向服务器请求数据的技术,而Comet则是一种服务器向页面推送数据的技术。两种实现Comet的方法:长轮询和流。

服务器发送事件

SSE(Server-Sent Events).
SSE API用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。服务器响应的MIME类型必须是text/event-stream,而且浏览器中的Javascript AP能解析格式输出。SSE支持短轮询、长轮询和HTTP流,而且能在断开连接时自动确定何时重新连接。

1、 SSE API
创建一个新的EventSource 对象,并传进一个入口点

1
var source = new EventSource('myevents.php');

注意:传入的URL必须与创建对象的页面同源(相同的URL模式、域及端口)。EventSource的实例有一个readyState属性,值为0表示正连接到服务器,值为1表示打开了连接,值为2表示关闭了连接。
三个事件:

  • open: 在建立连接时触发。

  • message: 在从服务器接收到新事件时触发。

  • error: 在无法建立连接时触发。

    1
    2
    3
    4
    source.onmessage = function(event){
    var data = event.data;
    //处理数据
    }

    服务器发送的数据以字符串形式保存在event.data中。
    默认情况下,EventSource对象会保持与服务器的活动连接。如果连接断开,还会重新连接。这就意味着SSE适合长轮询和HTTP流。如果想强制立即断开连接并且不再重新连接,可以调用close()方法。

    1
    2
    3
    4
    5
    6
    7
    8
    source.close();

    #### Web Sockets

    1、 Web Sockets API

    ```javascript
    var socket = new WebSocket('ws://www.example.com/server.php');

    必须给WebSocket构造函数传入绝对URL。

实例化WebSocket对象后,浏览器就会马上尝试连接,与XHR类似,WebSocket也有一个readyState属性:

  • WebSocket.OPENING(0): 正在建立连接
  • WebSocket.OPEN(1): 已经建立连接
  • WebSocket.CLOSING(2): 正关闭连接
  • WebSocket.CLOSE(3): 已经关闭连接

WebSocket没有readystatechange事件。不过,有其它事件对应着不同状态。readyState的值永远从0开始

1
socket.close();//关闭socket连接,调用close()之后,readyState的值,立即变为2(正在关闭),关闭连接后变成3

2、 发送和接收数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var socket = new WebSocket('ws://www.example.com/server.php');
socket.send('Hello world');


var message = {
time: new Date(),
text: 'Hello world'
}
socket.send(JSON.stringify(message));

//当服务器向客户端发送消息时,WebSocket对象就会触发message事件。
socket.onmessage = function(event){
var data = event.data;
//处理数据
}

3、 其它事件

1
2
3
4
5
6
7
8
9
10
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');
}