JavaScript权威指南读书笔记——第十八章 脚本化HTTP

本文介绍了如何使用XMLHttpRequest对象发起HTTP请求并处理响应。详细讲述了请求的不同部分组成,包括方法、URL、请求头和请求体等内容。同时,还探讨了如何处理服务器返回的响应,包括状态码、响应头及响应主体。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值