使用XMLHttpRequest
浏览器在XMLHttpRequest类上定义了它们的Http API。这个类的每个实例都表示一个独立的请求/响应对,并且这个对象的属性和方法允许指定请求细节和提取响应属性。
使用这个Http API必须做的第一件事就是实例化XMLHttpRequest对象:
var request = new XMLHttpRequest();
IE6中的XMLHttpRequest
在以前IE的版本中是使用ActiveX对象代替XMLHttpRequest。
if (window.XMLHttpRequest === undefined){
window.XMLHttpRequest = function(){
try{
//如果可用,则使用ActiveX对象的最新版本
return new ActiveXObject("Msxml2.XMLHttp.6.0");
}
catch(e1){
try{
//否则,回退到较旧的版本
return new ActiveXObject("Msxml2.XMLHttp.3.0");
}
catch(e2){
//否则,抛错
throw new Error("XMLHttpRequest is not supported");
}
}
}
}
一个Http请求由4个部分组成:
- Http请求的方法或“动作”
- 正在请求的URL
- 一个可选的请求头集合
- 一个可选的请求体
一个服务器返回的Http响应包含3部分:
- 一个数组和文字组成的状态码
- 一个响应头集合
- 响应主体
指定请求
创建XMLHttpRequest对象之后,发起Http请求的的下一步是调用XMLHttpRequest对象的open()方法指定这个请求的两个必须部分:方法和URL。
request.open("GET",//一个Http GET请求
"index.action");//URL
如果有请求头的话,请求进错的下个步骤是设置它。
request.setRequestHeader("Content-Type","text/plain");
使用XMLHttpRequest发起Http请求的最后一步是指定可选的请求主体并向服务器发送它。使用send()方法。
request.send(null);
取得响应
XMLHttpRequest对象的属性和方法
- status和statusText属性以数字和文本的形式返回Http状态码。
- 使用getResponseHeader()和getAllResponseHeaders()能查询响应头。不能获取cookie。
- 响应主体可以从responseText属性中得到文本形式的,从responseXML属性中得到Document形式的。
readyState是一个整数,它指定了Http请求的状态。第一列的符号是XMLHttpRequest构造函数定义的常量。
每次readyState属性改变都会触发readystatechange事件。
同步响应
XMLHttpRequest支持同步响应。如果把false作为第三个参数传递给open(),那么send()方法将阻塞知道请求完成。这种情况下,不需要使用事件处理程序:一旦send()返回,仅需要检查XMLHttpRequest对象的status和responseText属性。
响应解码
假设服务器使用像“text/plain”、”text/html”或“text/css”这样的MIME类型发送文本响应,然后我们使用XMLHttpRequest对象的responseText属性得到它。
如果服务器发送XML或XHTML文档作为其响应,你能通过responseXML属性获得一个解析形式的XML文档。这个属性的是值是一个Document对象。
如果服务器在“Content-Type”头中包含了错误的“charset”参数,那么XMLHttpRequest将使用错误的编码来解析响应,并且responseText中的字符可能是错的。可以使用XHR2定义打的overrideMineType()方法来解决问题。在低啊用send()之前把类型传递给overrideMimeType(),这个将使XMLHttpRequest忽略“Content-Type”头而使用指定的类型。
request.overrideMimeType("text/plain; charset=utf-8");
编码请求主体
表单的请求
对表单数据使用的编码方案相对简单:每个表单元素的名字和值纸箱普通的URL编码(使用十六进制转义码替换特殊字符),使用等号把编码后的名字和值分开,并使用“&”符号分开名/值对。一个简单表单的编码如下这样:
name1=value1&name2=value2
表单数据编码格式有一个正式的MIME类型
application/x-www/urlencoded
当使用POST方法提交这种顺序的表单数据时,必须设置“Cotent-Type”请求头为这个值。
使用表单编码数据发起一个HTTP POST请求
function postData(url, data, callback){
var request = new XMLHttpRequest();
request.open("POST",url);
request.onreadystatechange = function(){
if (request.readyState === 4 && callback){
callback(request);
}
}
request.setRequestHeader("Content-Type","application/x-www-urlencoded");
//encodeFormData()方法将JavaScript对象编码为表单传递数据的格式
request.send(encodeFormData(data));
}
使用表单编码数据发起一个HTTP GET请求
function getData(url, data, callback){
var request = new XMLHttpRequest();
request.open("GET",url+"?"+encodeFormData(data));
request.onreadystatechange = function(){
if (request.readyState === 4 && callback){
callback(request);
}
}
request.send(null);
}
JSON编码的请求
作为Web交换格式的JSON已经得到普及。
function postData(url, data, callback){
var request = new XMLHttpRequest();
request.open("POST",url);
request.onreadystatechange = function(){
if (request.readyState === 4 && callback){
callback(request);
}
}
request.setRequestHeader("Content-Type","application/json");
request.send(JSON.stringify(data));
}
XML编码的请求
fimctopm postQuery(url,callback){
var request = new XMLHttpRequest();
request.open("POST",url);
request.onreadystatechange = function(){
if (request.readyState === 4 && callback){
callback(request);
}
}
//Create an XML document
var doc = document.implementation.createDocument("","query",null);
var query = doc.documentElement;
var find = doc.createElement("find");
query.appendChild(find);
find.setAttribute("zipcode","value");
find.setAttribute("radius","value");
find.appendChild(dic.createTextNode("text"));
request.send(doc);
}
上传文件
HTML表单始终能上传文件,但不能使用XMLHttpRequest API做相同的事情。然后,XHR2 API允许通过send()方法传入File对象来实现上传功能。
没有File()对象的构造函数,脚本能通过获得用户当前选择文件的File对象。在支持File对象的浏览器中,每个<input type=”file”/>元素有一个files属性,他是File对象的类数组对象。
function(){
var elts = document.getElementsByName("input");
for (var i = 0; i < elts.length; i++){
var input = elts[i];
if (input.type != "file") continue;
input.addEventListener("change",function(){
var file = this.files[0];
if (!file) return;
var xhr = new XMLHttpRequest();
xhr.open("POST","url");
xhr.send(file);
}, false);
}
}
multipart/form-data请求
当HTML表单同时包含文件上传元素和其他元素时,浏览器不能使用普通的表单编码而必须使用称为“multipart/form-data”的特殊Content-Type来用POST方法提交表单。
XHR2定义了新的FormData API,它容易实现多部分请求主体。首先,使用FormData()构造函数创建FormData对象,然后按需多次调用这个对象的append()方法吧个体“部分”添加到请求中。最后,把FormData对象传递给send()方法。
function postFormData(url, data, callback){
if (typeof FormData === "undefined")
throw new Error("FormData is not implemented");
var request = new XMLHttpRequest();
request.open("POST",url);
request.onreadystatechange = function(){
if (request.readyState === 4 && callback){
callback(request);
}
}
var formData = new FormData();
for (var name in data){
if (!data.hasOwnProperty(name))
continue;
if (typeof value === "function")
continue;
formData.append(name,value);
}
request.send(formData);
}
HTTP进度事件
在调用send()时,出法单个loadstart事件。当正在加载服务器的响应时,XMLHttpRequest对象会发生progress事件,通常每隔50毫秒左右,所以可以使用这些事件给用户反馈请求事件。如果请求快速完成,它可能不会触发progress事件。当事件完成,会触发load事件。
HTTP请求无法完成有3种情况。如果请求超时,会触发timeout事件。如果请求终止,会触发abort事件。最后,想大多数重定向这样的网络错误会阻止请求完成,当这些情况发生时会触发error事件。
XHR2规范草案指出只要触发load、abort、timeout和error中的一个。浏览器就会触发loadend事件。
progress事件相关联的事件有3个有用的属性
- loaded属性是目前传输的字节数值
- total属性是自“Content-Lenght”头传输的数据的整体长度(单位是字节),如果不知道内容长度则为0
- lengthComputable属性为true表示知道内容长度,否则为false
request.onprogress = function(e){
if (e.lengthComputable)
progress.innerHTML = Math.round(100*e.loaded/e.total) + "% Complete";
}
终止请求和超时
可以通过调用XMLHTTPRequest对象的abort()方法来取消正在进行的HTTP请求。调用abort()方法会触发对象的abort事件。
XHR2定义了timeout属性来指定请求终止后的毫秒数,也定义了timeout事件用于当超时时发生时触发。
如果浏览器没实现timeout,我们就自己来实现。
function timeGetText(url,timeout,callback){
var request = new XMLHttpRequest();
var timeout = false;
var timer = setTimeout(function(){
timeout = true;
request.abort();
}, timeout);
request.open("GET", url);
request.onreadystatechange = function(){
if (request.readyState !== 4)
return;
if (timeout)
return;
clearTimeout(timer);
if (request.status === 200)
callback(request);
}
request.send(null);
}
借助<script>发送HTTP请求:JSONP
<script>可以作为一种Ajax传输机制:只需设置<script>元素的src属性,然后浏览器就会发送一个HTTP请求以下载src属性所指向的URL。
当通过<script>元素调用数据时,响应内容必须用JavaScript函数名和圆括号包裹起来。
handleResponse({a:"a",b:"b"});
function getJSONP(url, callback){
var cbnum = "cb" + getJSONP.couter++;
var cbname = "getJSONP." + cbnum;
if (url.indexOf("?") === -1)
url += "?jsonp=" + cbname;
else
url += "&jsonp=" + cbname;
var script = document.createElement("script");
getJSONP[cbnum] = function(response){
try{
callback(response);
}
finally{
delete getJSONP[cbnum];
script.parentNode.removeChild(script);
}
}
script.src = url;
document.body.appendChild(script);
}
getJSONP.couter = 0;
基于服务器端推送事件的Comet技术
EventSource对象,简化了Comet应用程序的编写可以传递一个URL给EventSource()构造函数,然后在返回的实例上监听消息事件。
var ticker = new EventSource("url");
ticker.onmessage = function(e){
var type = e.type;
//服务器发送过来的数据在e.data中
var data = e.data;
}