XMLHttpRequest 对象
function createXHR(){
if (typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
} else if (typeof ActiveXObject != "undefined"){
if (typeof arguments.callee.activeXString != "string"){
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 ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex){
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error("No XHR object available.");
}
}
这个函数中新增的代码首先检测原生XHR 对象是否存在,如果存在则返回它的新实例。如果原生
对象不存在,则检测ActiveX 对象。如果这两种对象都不存在,就抛出一个错误。然后,就可以使用下
面的代码在所有浏览器中创建XHR 对象了。
var xhr = createXHR();用法
第一个方法是open(),它接受3 个参数:要发送的请求的类型
(”get”、”post”等)、请求的URL 和表示是否异步发送请求的布尔值。下面就是调用这个方法的例子。
xhr.open(“get”, “example.php”, false);
这行代码会启动一个针对example.php 的GET 请求。有关这行代码,需要说明两点:一是URL
相对于执行代码的当前页面(当然也可以使用绝对路径);二是调用open()方法并不会真正发送请求,
而只是启动一个请求以备发送。要发送特定的请求,必须像下面这样调用send()方法:
xhr.open(“get”, “example.txt”, false);
xhr.send(null);
这里的send()方法接收一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送
数据,则必须传入null,因为这个参数对有些浏览器来说是必需的。调用send()之后,请求就会被分
派到服务器。
xhr.open(“get”, “example.txt”, false);
xhr.send(null);
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert(“Request was unsuccessful: ” + xhr.status);
}
get请求
使用GET 请求经常会发生的一个错误,就是查询字符串的格式有问题。查询字符串中每个参数的名
称和值都必须使用encodeURIComponent()进行编码,然后才能放到URL 的末尾;而且所有名-值对
儿都必须由和号(&)分隔,如下面的例子所示。
xhr.open(“get”, “example.php?name1=value1&name2=value2”, true);
下面这个函数可以辅助向现有URL 的末尾添加查询字符串参数:
function addURLParam(url, name, value) {
url += (url.indexOf("?") == -1 ? "?" : "&");
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
下面是使用这个函数来构建请求URL 的示例。
var url = “example.php”;
//添加参数
url = addURLParam(url, “name”, “Nicholas”);
url = addURLParam(url, “book”, “Professional JavaScript”);
//初始化请求
xhr.open(“get”, url, false);
在这里使用addURLParam()函数可以确保查询字符串的格式良好,并可靠地用于XHR 对象。post请求
POST 数据的格式与查
询字符串格式相同。如果需要将页面中表单的数据进行序列化,然后再通过XHR 发送到服务器,那么
就可以使用第14 章介绍的serialize()函数来创建这个字符串:
function submitData(){
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("post", "postexample.php", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var form = document.getElementById("user-info");
xhr.send(serialize(form));
}
这个函数可以将ID 为”user-info”的表单中的数据序列化之后发送给服务器。而下面的示例PHP
文件postexample.php 就可以通过$_POST 取得提交的数据了:
<?php
header("Content-Type: text/plain");
echo <<<EOF
Name: {$_POST[‘user-name’]}
Email: {$_POST[‘user-email’]}
EOF;
?>
同源策略是对XHR 的一个主要约束,它为通信设置了“相同的域、相同的端口、相同的协议”这一
限制。试图访问上述限制之外的资源,都会引发安全错误,除非采用被认可的跨域解决方案。这个解决
方案叫做CORS(Cross-Origin Resource Sharing,跨源资源共享),IE8 通过XDomainRequest 对象支持CORS,其他浏览器通过XHR 对象原生支持CORS。图像Ping 和JSONP 是另外两种跨域通信的技术,
但不如CORS 稳妥。
Comet 是对Ajax 的进一步扩展,让服务器几乎能够实时地向客户端推送数据。实现Comet 的手段
主要有两个:长轮询和HTTP 流。所有浏览器都支持长轮询,而只有部分浏览器原生支持HTTP 流。SSE
(Server-Sent Events,服务器发送事件)是一种实现Comet 交互的浏览器API,既支持长轮询,也支持
HTTP 流。Web Sockets 是一种与服务器进行全双工、双向通信的信道。与其他方案不同,Web Sockets 不使用
HTTP 协议,而使用一种自定义的协议。这种协议专门为快速传输小数据设计。虽然要求使用不同的
Web 服务器,但却具有速度上的优势。