/**
* @author 《JavaScript权威指南》,蓝文雄解读整理
* 声明:时间精力水平有限,本文档存在错误
* 但依然可作为思路文档使用,实际开发可使用我封装的
http://www.cnblogs.com/vincent-lwx/archive/2008/08/19/1270998.html
* 第一步:创建XMLHTTPReuqest对象
* 第二步:指定XMLHTTPReuqest三种请求
* 第三步:同步或异步获取并处理服务器响应(响应处理参考以下文档说明)
*
* XMLHTTPReuqest.open():第三个参数为true(默认)/false--异步/同步(可选):
*
* (1)同步请求
* 采用队列请求方式。与异步不同,无需考虑请求状态码的改变,只需判断HTTP状态代码:
* if(request.status==200){
* if(request.getResponseHeader("Content-Type")=="text/xml"){
var doc=request.responseXML;
}
}
else{
alert("Error"+request.status+":"+request.statusText);
}
* (2)异步请求
* 需要指定onreadystatechange:0(open()没有调用)、1(open()调用但send()没发送)、2(send()调用但服务器没响应)、3(正在接受服务器端数据,因浏览器而异)
* 由于浏览器支持的差异性只考虑readyState==4(特别readyState==3,firefix多次调用onreadystatechange时间句柄,而IE没有)
* 异步请求、处理响应参考各个工具函数
*
* 本文档介绍了处理不同编码的响应方式
* 本文档介绍了使请求过期的方法
*/
* XMLHTTPReuqest跨平台请求工具函数
*/
HTTP._factories=[ //针对不同浏览器的XMLHttpRequest对象数组
function(){return new XMLHttpRequest();},
function(){return new ActiveXObject("Msxml2.XMLHTTP");},
function(){return new ActiveXObject("Microsoft.XMLHTTP");}
];
HTTP._factory=null;
HTTP.newRequest=function(){
if(HTTP._factory!=null) return HTTP._factory();
for(var i=0;i<HTTP._factories.length;i++){
try{
var factory=HTTP._factories[i];
var request=factory();
if(request!=null){
HTTP._factory=factory;
return request; //成功创建XMLHttpRequest
}
}
catch(e){
continue;
}
}
HTTP._factory=function(){
throw new Error("XMLHTTPRequest not supported!"); //浏览器不支持XMLHttpRequest,抛出错误
}
HTTP._factory();
}
/**
* HTTP.GET两个工具函数:分别获取text、xml响应
* callback:处理响应文本、xml的函数(需手工建立)
*/
HTTP.getText=function(url,callback){
var request=HTTP.newRequest();
request.onreadystatechange=function(){
if(request.readyState==4 && request.status==200)
callback(request.responseText); //请求正常,callback函数托管响应
}
request.open("GET",url);
request.send(null);
}
HTTP.getXML=function(url,callback){
var request=HTTP.newRequest();
reuqest.onreadystatechange=function(){
if(request.readyState==4 && request.status==200) //请求成功
callback(request.responseXML); //请求正常,callback函数托管响应
}
request.open("GET",url);
request.send(null);
}
/**
* HTTP.getHeaders()工具函数:请求获取HTTP头部并解析HTTP头部键值对并存储为一个JavaScript对象的属性和值
* callback:处理HTTP.parseHeaders函数返回的JavaScript对象(需手工建立)
* errorHandler:错误句柄函数,处理404或者其他错位代码(需手工建立)
* HTTP.parseHeaders:解析HTTP头部键值函数,返回JavaScript对象
* */
HTTP.getHeaders=function(url,callback,errorHandler){
var request=HTTP.newRequest();
reuqest.onreadystatechange=function(){
if(request.readyState==4){
if(request.status==200){
callback(HTTP.parseHeaders(request)); //请求正常,HTTP.parseHeaders函数托管响应
}
}else{
if(errorHandler) errorHandler(request.status,request.statusText); //请求异常
else callback(null);
}
}
request.open("HEAD",url);
request.send(null);
};
HTTP.parseHeaders=function(request){
var headerText=request.getAllResponseHeaders(); //获取头部键值数组
var headers={}; //返回值
var ls=/^\s*/; //正则表达式
var ts=/\s*$/;
var lines=headerText.split("\n");
for(var i=0;i<lines.length;i++){
var line=lines[i];
if(line.length==0) continue; //忽略空行,否则开始解析
var pos=line.indexOf(':');
var name=line.substring(0,pos).replace(ls,"").replace(ts,"");
var value=line.substring(0,pos+1).replace(ls,"").replace(ts,"");
headers[name]=value; //填充返回值
}
return headers;
};
/**
* HTTP.POST()工具函数:基本形式与HTTP.getHeaders()类似,但需要设置请求头部信息、请求体数据
* HTTP.encodeFormatData:格式化并返回请求体数据
* HTTP._getResponse:处理响应,参考以下文档说明
* */
HTTP.post=function(url,callback,errorHandler){
var request=HTTP.newRequest();
reuqest.onreadystatechange=function(){
if(request.readyState==4){
if(request.status==200){
callback(HTTP._getResponse(request)); //请求正常
}
}else{
if(errorHandler) errorHandler(request.status,request.statusText); //请求异常
else callback(null);
}
}
request.open("POST",url); //指定请求格式,并且设置请求头部信息
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
request.send(HTTP.encodeFormatData(values));
//HTTP.encodeFormatData(values)函数返回请求体数据
};
HTTP.encodeFormatData=function(data){
var pairs=[];
var regexp=/%20/g;
for(var name in data){
var value=data[name].toString();
var pair=encodeURIComponent(name).replace(regexp,"+")+
'='+encodeURIComponent(value).re.replace(regexp,"+");
pairs.push(pair);
}
return pairs.join('&');
};
/**
* 处理请求响应:TEXT\HTML\XML\JSON编码
* XML响应:服务器必须使用MIME类型的"text/xml"标示XML文档,保证XMLHttpRequest把响应XML解析为doxument对象中,然后使用DOM方法处理
* HTML响应:和TEXT一样使用request.responseText访问,然后使用文档元素innerHTML属性处理
* JSON响应:使用eval()解析JSON编码的数据,注意安全问题,防止服务器发送恶意的可执行的脚本!安全的方法是使用JSON解码器(http://json.org/)。
* 下面提供一个简单的通用文档
* */
HTTP._getResponse=function(request){
switch(request.getRequestHeader("Content-Type")){
case "text/xml":
return request.responseXML;
case "text/json":
case "text/javascript":
case "application/javascript":
case "application/x-javascript":
return eval(request.responseText);
default:
return request.responseText;
}
}
/**
* 在某些场景中需要手动设置请求的过期,而XMLHttpRequest没有提供如此的方法
* XMLHttpRequest发布HTTP请求时,使用window.setTimeout()设置过期值和window.clearTimeout()取消过期设置
* 使用XMLHttpRequest.abort()取消请求
* 现在提供一个工具函数HTTP.get():展示过期技术(options)的使用,同时整合了前面部分工具函数的功能
* 特色:允许调用者指定可选的回调函数,当onreadystatechange句柄使用4以外的其他readyState值被调用时,触发这个回调函数
* (Firefix在状态3中多次调用这个句柄onreadystatechange向用户显示下载反馈)
* */
HTTP.get=function(url,callback,options){
var request=HTTP.newRequest(); //创建XMLHttpRequest对象
var n=0;
var timer;
if(options.timeout) //请求过期设置
timer=setTimeout(function(){
request.abort();
if(options.timeoutHandler)
options.timeoutHandler(url);
},
options.timeout);
request.onreadystatechange=function(){ //状态改变处理函数
if(request.readyState==4){ //服务器响应完成
if(timer) clearTimeout(timer); //清除过期设置
if(request.status==200){ //请求成功开始处理响应
callback(HTTP._getResponse(request));
}
else{
if(options.errorHandler) //请求失败开始处理失败句柄
options.errorHandler(request.status,request.statusText);
else callback(null);
}
}
else if(options.progrressHandler){ //如果指定状态值<4时的请求过程处理句柄
options.progressHandler(++n); //0(open()没有调用)、1(open()调用但send()没发送)、2(send()调用但服务器没响应)、3(正在接受服务器端数据,因浏览器而异)
}
}
var target=url;
if(options.parameters) //如果请求有参数需要发送,构造请求url
target += "?" + HTTP.encodeFormatData(options.parameters);
request.open("GET",target);
request.send(null);
};