XMLHttpRequest对象
Ajax的核心是XMLHttpRequest。
//适用于IE7之前的版本
function creatXHR(){
if(typeof arguments.callee.activeXString != "string"){
var version = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"],i,len;
for(i=0,len=version.length;i<len;i++){
try{
new ActiveXObject(version[i]);
arguments.callee.activeXString = version[i];
break;
} catch (ex){
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
支持更高版本的写法:
function creatXHR(){
if(typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
} else if (typeof ActiveXObject != "undefined"){
if (typeof arguments.callee.activeXString != "string") {
var version = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"], i, len;
for (i = 0, len = version.length; i < len; i++) {
try {
new ActiveXObject(version[i]);
arguments.callee.activeXString = version[i];
break;
} catch (ex) {
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error("No XHR object available.");
}
}
这个函数中新增的代码首先检测原生XHR对象是否存在。如果存在则返回它的 新实例。如果原生对象不存在,则检测ActiveX对象。如果这两种对象都不存在,就抛出一个错误。然后就可以使用以下的代码在所有浏览器中创建XHR对象了
var xhr = createXHR();
XHR的用法
使用xhr对象时,要调用 的第一个方法是open(),它接受3个参数:要发送的请求类型,请求的URL和表示是否异步发送请求的布尔值。
xhr.open("get","example.php",false)
要发送特定的请求,像下面这样调用 seng()方法
xhr.open("get","example.php",false)
xjr.send(null);
这里的send()方法接收一个参数,即要作为请求的主体发送的数据。如果不需要通过请求主体发送数据,则必须传入null.
相关的属性:
responseText:作为响应主体被返回的文本
responseXML:如果响应的内容是"text/xml"或"application/xml",这个属性中将保存包含着响应数据的XML DOM文档
status: 响应的 HTTP状态
statusText:HTTP状态的说明
在接收到响应后,第一步是检查status属性,以确定响应已经 成功返回。一般来说,将HTTP状态代码为200作为成功的标志。
xhr.open("get", "example.txt", false);
xhr.send(null);
if ((xhr.status >= 200 & xhr.status < 300) || xhr.status == 304) {
alert(xhr.responsText);
} else {
alert("Request was unsuccessful:" + xhr.status);
}
只要readyState属性的值由一个值变成另一个值,都会触发一readystatechange事件。可以利用这个事件来检测每次状态变化
后的readyState的值.
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()方法来取消异步请求
xhr.abort()
HTTP头部信息
每个HTTP请求和响应都会带有相应的头部信息。
默认请问下,在发送xhr请求的同时, 还会发送下列头部信息:
Accept:浏览器能够处理的内容类型
Accept-Charset:浏览器能够显示的字符集
Accept-Encoding:浏览器能够处理的压缩编码
Accept-Language:浏览器 与服务器之间连接的类型
Cookie:当前页面设置所在的域
Referer:发出请求的 页面的URI。
User-Agent:浏览器的用户代理字符串
使用setRequestHeader()方法可以设置自定义的请求头部信息。这个方法接受两个参数:头部字段的名称和头部字段的值。要成功发送头部请求,必须在调用 open()之后且调用 send()之前,如下:
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.setRequestHeader("MyHeader","MyValue");
xhr.send(null);
调用XHR对象的getResponseHeader()方法并传入头部字段名称,可以取得相应的响应头部信息。而调用getAllResponseHeaders()方法可以取得一个包含所有头部信息的长字符串。
var myHeader = xhr.getResponseHeader("MyHeader");
var allHeader = xhr.getAllResponseHeader();
GET请求
get请求是最常见的请求类型,最常用于向服务器查询某些信息。
使用get请求经常会发生一些错误,就是查询字符串的格式有问题。
xhr.open("get","example.php?name1=value1&namne2=value2",true)
下面这个函数可以辅助向 现有URL的末尾添加查询字符串参数:
function addURLParam(url,name,value){
url += (url.indexOf("?") == -1 ? "?" : "&");
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return null;
}
这个addURLParam函数接收3个参数:要添加参数的URL,参数的名称和参数的值。
下面是使用这个函数来构建请求URL的示例:
var url = "example.txt";
//添加参数
url = addURLParam(url, "namne", "Nicholas");
url = addURLParam(url, "book", "Prefessional Javascript");
//初始化请求
xhr.open("get", url, false);
POST请求
通常用于向服务器发送应该被保存的数据。
POST请求应该把数据作为请求的主体提交,而GET请求传统上不是这样。
xhr.open("post","example.php",true);
发送POST请求的第二步就是向send()方法中传入某些数据。
function submitData(){
var xhr = creatXHR();
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));
FormDat
FormData为序列化表单以及创建与表单格式相同的数据提供了便利。下面的代码创建了一个FormData对象,并向其中添加了一些数据:
var data = new FormData();
data.append("name","Nicholas");
这个append方法接收两个参数:键和值
也可以用表单元素的数据先向其中填入键值对:
var data = new FormData(document.forms[0]);
创建了FormData实例后,可以将它直接传给XHR的send()方法,如下;
var xhr = creatXHR();
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);
var form = document.getElementById(user-info);
xhr.send(new FormData(form));
使用FormData的方便之处体现在不必明确地在XHR对象上设置请求头部。XHR对象能够识别传入的数据类型是FormData的实例,并配置适当的头部信息。
超时设定 timeout属性
IE8为XHR对象添加了一个timeout属性,表示请求在等待响应多少毫秒之后就终止。
var xhr = creatXHR();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
try{
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("Request was unsuccessful:" + xhr.status);
}
} catch(ex){
//假设由ontimeout事件处理程序处理
}
}
}
xhr.open("post","timeout.php",true);
xhr.timeout = 1000;//将超时设置为1s
xhr.ontimeout = function(){
alert("Request did not return in a second.")
};
overrideMimeType()方法
该方法用于重写XHR响应的MIME类型。
比如,服务器返回的MIME类型是text/plain,但数据中实际包含的是XML。根据MIME类型 ,即使数据是XML,responseXML属性中仍然是null。通过调用overrideMimeType()方法,可以保证把响应当作XML而非纯文本来处理。
var xhr = createXHR();
xhr.open("get","text.php",true);
xhr.overrideMimeType("text/xml");
xhr.send(null);
进度事件
6个进度事件:
loadstart:在接收到响应数据的第一个字节时触发
progress:在接收响应期间持续不断地触发
error:在请求发生错误时触发
abort:在因为调用abort()方法而终止连接时触发
load:在接收到完整的响应数据时触发
loadend:在通信完成或者触发error,abort或事件后触发
跨资源共享 CORS
cors的基本思想是,就是用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
IE对CORS的实现
所有XDR请求都是异步执行,不能用它来创建同步请求。如下:
var xdr = new XDomainRequest();
xdr.onload = function() {
alert(xdr.responseText);
};
xdr.open("get","http://www.somewhere-else.com/page/");
xdr.send(null);
要检测错误,可以像下面指定一个onerror事件处理程序
var xdr = new XDomainRequest();
xdr.onload = function() {
alert(xdr.responseText);
};
xdr.onerror = function(){
alert("An error occurred.");
}
xdr.open("get","http://www.somewhere-else.com/page/");
xdr.send(null);
在请求 返回前调用abort()方法可以终止请求:
var xdr = new XDomainRequest();
xdr.onload = function() {
alert(xdr.responseText);
};
xdr.onerror = function(){
alert("An error occurred.");
}
xdr.timeout = 1000;
xdr.ontimeout = function(){
alert("Request took too long.");
}
xdr.open("get","http://www.somewhere-else.com/page/");
xdr.send(null);
为支持POST请求,XDR对象提供了contentType属性,用来表示发送数据的格式。
var xdr = new XDomainRequest();
xdr.onload = function() {
alert(xdr.responseText);
};
xdr.onerror = function() {
alert("An error occurred.");
}
xdr.open("post", "http://www.somewhere-else.com/page/");
xdr.contentType = "application/x-www-form-urlencoded";
xdr.send("name=vauel1&name2=value2");
其他浏览器对CORS的实现
var xhr = creatXHR();
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);
}
}
}
xdr.open("get", "http://www.somewhere-else.com/page/",true);
xdr.send(null);
Preflighted Reqeusts
该透明服务器验证机制支持开发人员使用自定义的头部、GET或POST之外的方法,以及不同类型的主体内容。
带凭据的请求
默认情况下,跨源请求不 提供凭据(cokie,HTTP认证及客户端SSL证明等)。通过withCredentials属性设置为true.可以指定某个请求应该发送凭据。如果服务器接受凭据的请求,会用下面的HTTP头部来响应:
Access-Control-Allow-Credentials: true;
跨浏览器的CORS
检测XHR是否支持CORS的最简单的方式,就是检查是否存在withCredentials属性。再结合检测XDomainRequest对象是否存在,就可以兼顾所有浏览器了。
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("widthCredentials" in xhr) {
xhr.open(method, url, true);
} else if (typeof XDominRequest != "undefined") {
xhr = new XDominRequest();
xhr.open(method, url);
} else {
xhr = null;
}
return xhr;
}
var request = createCORSRequest("get", "http://www.somewhere-else.com/page/");
if (request) {
request.onload = function() {
//...
};
request.send();
}
XMLHttpRequest和XDominRequest这两个对象的共同的属性/方法如下:
abort():用于停止正在进行的请求
onerror:用于检测错误
onload:用于检测成功
responseText:用于取得响应内容
send():用于发送请求
图像Ping
动态创建图像经常用于图像Ping.图像Ping是与服务器进行简单,单向的跨域通信的一种方式。请求的数据是通过查询字符串形式发送的,而响应可以是任意内容。
var img = new Image();
img.onload = img.onerror = function(){
alert("Done!");
};
img.src = "http://www.example.com/test?name=Nicholas";
JSONP
JSONP是JSON with padding(填充式JSON或参数式JSON)的简写。
JSONP由两部分组成:回调函数和数据。
function handleResponse(response){
alert("You re at Ip address" + response.ip + ",whihc is in " + response.city + "," + response.region_name);
}
var script = document.createElement("script");
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script,document.body.firstChild);
这个例子通过查询地理定位服务来显示你的IP地址和位置信息。
Comet
Ajax是一种从页面向服务器请求数据的技术,而Comet则是一种服务器向页面推送数据的技术。
有两种实现Comet的方式:长轮询和流。
通过侦听readystatechange事件检测readyState的值是否为3,就可以利用XHR对象实现HTTP流。随着不断从服务器接收数据,readyState的值会周期性地变为3.当readyState值变为3时,responseText属性中就会保存接收到的所有数据。此时,就需要比较 较此前接收到的数据,决定从什么位置开始取得最新的数据。使用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("streaming.php",function(data){
alert("Received: " + data);
},function(data){
alert("Done!");
});
这个createStreamingClient()函数接收三个参数:要连接的URL,在接收到数据时 调用的函数以及关闭连接时调用的函数。有时候,当连接关闭时,很可能还需要重新建立,所以关注连接什么时候关闭还是有必要的。
服务器发送事件 SSE
SSE是围绕只读Comet交互推出的API或者模式。
SSE API用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。
服务器响应的MIME类型必须是text/event-stream.
SSE支持短轮询,长流询和HTTP流。
SSE API
要预定新的事件流,首先要创建一个新的EVentSource对象,并传进一个入口点:
var source = new EventSource("myevents.php");
注意,传入的URL必须与创建对象的页面同源(相同的URL模式,域及端口)。EventSource的实例有一个readyState属性,值为0表示正连接到服务器,值为1表示打开了连接,值为2表示关闭了连接。另外还有3个事件:
open:在建立连接时触发
message:在从服务器接收到新事件时触发
error:在无法建立连接时触发
source.onmessage = function(event){
var data = event.data;
//处理数据
}
source.close();//断开连接
事件流
所谓的服务器事件会通过一个持久的HTTP响应发送,这个响应的MIME类型为text/event-stream.响应的格式为纯文本。
data: foo
data: bar
data: foo
data: bar
Web Sockets
Web Sockets的目标是在一个单独的持久连接上提供全双工、双向通信。
1. Web SocketsAPI
要创建Web Socket,先实例一个WebSocket对象并传入要连接的URL:
var socket = new WebSocket("ws://www.example.com/server.php");
Web Socket 表示当前状态的属性:
WebSocket.OPENING(0): 正在建立连接
WebSocket.OPEN(1):已经建立连接
WebSocket.CLOSEING(2):正在关闭连接
WebSocket.CLOSE(3):已经关闭连接
WebSocket没有readystatechange事件,不过,它有其他事件,对应着不同的状态。readyState的值永远从0开始。
要关闭Web Socket连接:
socket.close();
发送和接收数据
var socket = new WebSocket("ws://www.example.com/server.php");
socket.send("Hello World!");
因为Web Socket只能通过连接发送纯文本数据,所以对于复杂的数据结构,在通过连接之前,必须进行序列化:
var message = {
time: new Data(),
text: "Hello World!",
clientId: "asdfp8734rew"
};
socket.send(JSON.stringify(message));
当服务器向客户端发来消息时,WebSocket对象就会触发message事件:
socket.onmessage = function(event){
var data = event.data;
//处理数据
}
WebSocket其他事件
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.");
};
可以记录到日志中以便将来分析:
socket.onclose = function(event){
console.log("Was clear?" + event.wasClean + "Code = " + event.code + " Reason= " + event.reason);
};
Ajax是无需刷新页面就能够从服务器取得数据的一种方法。从以下几方面了解:
(1).负责Ajax运作的核心对象是XMLHttpRequest(XHR)对象
(2).XHR对象由微软最早在IE5中引入,用于通过Javascript从服务器取得XML对象
(3).在此之后,各浏览器都实现了相同的特性,使XHR成为了Web的一个事实标准
(4).虽然浏览器的实现之间有差异,还是相对规范,放心使用
Comet是对Ajax的进一步扩展,让服务器几乎能够实时地向客户端 推送数据。实现Comet手段主要有两个:长轮询和HTTP流。
Web Sockets是一种与服务器进行全双工,双向通信的信道。与其他方案不同,它不使用HTTP,而是使用一种自定义的。具有速度上的优势。