XMLHttpRequest对象

XMLHttpRequest对象

目前状态:

​ XHR对象的API被普遍认为比较难用,自Fetch API 诞生以后迅速称为了XHR 更现代的替代标准 。实际开发中,应该尽可能使用fetch()。

作用:

​ XHR 对象为开发者提供了原生的浏览器通信能力

使用XHR

所有现代浏览器都通过XMLHttpRequest 构造函数原生支持XHR对象:

let xhr = new XMLHttpRequest();
// 要使用xhr对象首先调用open()方法
/*
open 方法参数说明:
第一个参数为 请求类型 可选值为(get,post,put 等)
第二个参数为请求的URL
第三个参数为 表示请求是否异步  (布尔值)
*/
xhr.open("get","example.php",false);

上边这行代码可以向example.php 发送一个同步的GET请求。还需要说明几点:

  • 这里的URL是相对于代码所在页面的,当然也可以使用绝对URL.
  • 调用open()不会实际发送请求,只是为了发送请求做好准备。

同源策略 :只能访问同源URL,也就是域名相同、端口相同、协议相同。如果请求的URL与发送请求的页面再任何方便有所不同,则会抛出安全错误。

要发送定义好的请求,必须向下面这样调用send()方法:

xhr.open("get","example.txt",false);
xhr.send(null); 

send()方法接收一个参数,是作为请求体发送的数据。如果不需要发送请求体,则必须传null,因为这个参数在某些浏览器中是必需的。 调用send()之后,请求就会发送到服务器。

因为这个请求时同步的, 所以JavaScript 代码会等待服务器响应之后再继续执行。收到响应后,XHR 对象的以下属性会被填充上数据。

  • responseText: 作为响应体返回的文本。
  • responseXML:如果响应内容类型时“text/xml” 或“application/xml”,那就是包含响应数据的XMLDOM文档。
  • status: 响应的HTTP状态.
  • statusText:响应的HTTP状态描述。

收到响应后,第一步要检查status属性以确保响应成功返回。一般来说,HTTP状态码为2xx表示成功。此时,responseText 或 responseXML(如果内容类型正确) 属性中会有内容。如果HTTP 状态码是304,则表示资源未修改过,是从浏览器缓存中直接拿取的。当然这也意味着响应有效。为确保收到正确的响应,应该检查这些状态,如下所示:

xhr.open('get','example.txt',false);
xhr.send(null);
/*
为确定下一步该执行什么操作,最好检查status 而不是statusText属性,
因为后者已经被证明在跨浏览器的情况下不可靠
无论是什么响应内容类型,responseText 属性始终会保存响应体,而responseXML则对于非XML数据是null
*/
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
  alert(xhr.responseText);
}else{
  alert("请求失败:"+xhr.status);
}

异步同步

虽然可以向前面例子一样发送同步请求,但是多数情况下最好使用异步请求,这样可以不阻塞JavaScript代码继续执行。XHR 对象有一个readyState属性,表示当前处在请求/响应过程的那个阶段。这个属性有如下可能的值。

  • 0:未初始化(Uninitialized) 。尚未调用open() 方法。
  • 1:已打开(Open)。 已调用open() 方法,尚未调用send() 方法。
  • 2:已发送(Sent)。 已调用send()方法 ,尚未收到响应。
  • 3:接收中(Receiving)。已经收到部分响应。
  • 4:完成(Complete)。 已经收到所有响应,可以使用了。

每次readyState 从一个值变成另一个值,都会触发readystatechange事件。可以借此机会检查readyState 的值。一般来说,我们唯一关心的readyState 值是4,表示数据已就绪。为保证跨浏览器兼容,onreadystatechange事件处理程序应该在调用open()之前赋值。例子:

let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    if(xhr.readyState == 4){
        if((xhr.status >= 200 && xhr.status < 300)|| xhr.status == 304){
            alert(xhr.responseText);
        }else{
            alert("请求失败:"+xhr.status);
        }
    }
};
xhr.open('get','example.txt',true);
xhr.send(null);
//在收到响应之前 如果向取消异步请求,可以调用abort() 方法:
xhr.abort();

HTTP头部

每个HTTP请求和响应都会携带一些头部字段,这些字段可能对开发者有用。XHR对象会通过一些方法暴露与请求和响应相关的头部字段。

默认情况下,XHR请求会发送以下头部字段。

  • Accept:浏览器可以处理的内容类型
  • Accept-Charset: 浏览器可以显示的字符集
  • Accept-Encoding: 浏览器可以处理的压缩编码类型
  • Accept-Language: 浏览器使用的语言
  • Connection: 浏览器与服务器的连接类型。
  • Cookie: 页面中设置的Cookie。
  • Host: 发送请求的页面所在的域
  • Referer: 发送请求的页面URI.注意,这个字段在HTTP规范中拼错了,所以考虑到兼容性也必需将错就错。(正确拼写应该是Referrer)
  • User-Agent:浏览器的用户代理字符串

不同浏览器发送的确切头部字段可能各不相同,但这些通常都是会发送的。如果需要发送额外的请求头部,可以使用setRequestHeader()方法。这个方法接收两个参数:头部字段的名称和值。为保证请求头部被发送,必需在open() 之后、send()之前调用setRequestHeader(),例子:

let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    if((xhr.status >= 200 && xhr.status<300 ) || xhr.status == 304){
        alert(xhr.responseText);
    }else{
        alert(xhr.status);
    }
}
xhr.open('get','example.php',true);
xhr.setRequestHeader('MyHeader','MyValue');
xhr.send(null);

可以使用getResponseHeader() 方法从XHR对象获取响应头部,只要传入要获取头部的名称即可。

可以使用getAllResponseHeaders()方法从XHR对象获取所有响应的头部信息。不需要参数。

POST请求

用于向服务器发送应该要保存的数据。每个post请求都应该在请求体中携带提交的数据,而GET请求则不用。POST请求的请求体可以包含非常多的数据,而且数据可以是任意格式。要初始化POST请求,open方法的第一个参数要传“post” 比如:

xhr.open("post","example.php",true);

接下来就是要给send()方法传入要发送的数据。因为XHR最初主要设计用于发送XML,所以可以传入序列化之后的XML DOM文档作为请求体。当然,也可以传入任意字符串。

默认情况下,对服务器而言,POST请求与提交表单是不一样的。服务器逻辑需要读取原始POST数据才能取得浏览器发送的数据。不过,可以使用XHR模拟表单提交。为此,第一步需要把Content-Type头部设置为“application/x-www-formurlencoded” ,这是提交表单时使用的内容类型。第二步是创建对应格式的字符串。POST数据此时使用与查询字符串相同的格式。如果网页中确实有一个表单需要序列化并通过XHR发送到服务器可以使用serialize()函数来创建响应的字符串

xhr.open("post",'example.php',true);
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
let form = document.getElmentById('user-info');
xhr.send(serialize(form));

POST请求相比GET请求要占用更多资源。从性能方面说,发送相同数量的数据,GET 请求比POST请求要快两倍。

XMLHttpRequest Level 1 and XMLHttpRequest Level 2

XMLHttpRequest Level 1 只是把已经存在的XHR对象的实现细节明确了一下。

XMLHttpRequest Level 2 进一步发展了XHR对象。

FormData 类型

现代Web 应用程序中 经常需要对表单数据进行序列化,因此XMLHttpRequest Level 2 新增了FormData 类型。FormData 类型便于表单序列化,也便于创建与表单类似格式的数据然后通过XHR发送。下面的代码创建了一个FormData对象,并填充了一些数据:

let data = new FormData();
data.append("name",'张三');

append方法接收两个参数:键和值,相当于表单字段名称和该字段的值。可以像这样添加任意多个键/值对数据。此外,通过直接给FormData 构造函数传入一个表单元素,也可以将表单中的数据作为键/值对填充进行:

let data  = new FormData(document.forms[0]);
// 也可以直接传给XHR对象的send()方法
let xhr = new XMLHttpRequest();
xhr.onreadystatechange= function(){
    if((xhr.status >= 200 && xhr.status <300)||xhr.status == 304){
        alert(xhr.responseText);
    }else{
        alert(xhr.status);
    }
}
xhr.open('post','example.php',true);
let form = document.getElementById("user-info");
xhr.send(new FormData(form));

使用FormData的另一个方便之处是不再需要给XHR对象显式设置任何请求头部了。XHR对象能够识别作为FormData 实例传入的数据类型并自动配置响应的头部。

超时

IE8 给XHR对象增加了一个timeout 属性,用于表示发送请求后等待多少毫秒,如果响应不成功就中断请求。之后所有浏览器都在自己的XHR实现中增加了这个属性。在给timeout 属性设置了一个时间且在该时间过后没有收到响应时,XHR对象就会触发timeout事件,调用ontimeout事件处理程序。这个特性后来也被添加到了XMLHttpRequest Level 2 规范。例子:

let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    if(xhr.readyState == 4){
        try{
            if((xhr.status >=200 && xhr.status <300 )|| xhr.status == 304){
                alert(xhr.responseText);
            }else{
                alert(xhr.status);
            }
        }catch(ex){
            //假设由ontimeout 处理
            console.log('catch',ex)
        }
    }
}
xhr.open('get','timeout.php',true);
xhr.timeout = 1000;
xhr.ontimeout = function(){
    alert("请求超时")
}
xhr.send(null);

这个例子演示了使用timeout设置超时。给timeout 设置1000毫秒意味着,如果请求没有在1秒内返回则会中断。此时则会触发ontimeout事件处理程序,readyState 仍然会变成4,因此也会调用onreadystatechange事件处理程序。不过,如果在超时之后访问status属性则会发生错误,为做好防护,可以把检查status属性的代码封装在try/catch 语句中。

overrideMimeType()方法

Firefox 首先引入了overrideMimeType()方法用于重写XHR响应的MIME类型。这个特性后来也被添加到了XMLHttpRequest Level 2。因为响应返回的MIME 类型决定了XHR对象如何处理响应,所以如果有办法覆盖服务器返回的类型,那么是由帮助的。

假设服务器实际发送了XML数据,但响应头设置的MIME类型是text/plain。结果就会导致虽然数据是XML,但responseXML属性值是null.此时调用overrideMimeType()可以保证将响应当成XML而不是纯文本来处理:

let xhr = new XMLHttpRequest();
xhr.open("get",'text.php',true);
xhr.overrideMimeType("text/xml");
xhr.send(null);

这个例子强制让XHR把响应当成XML而不是纯文本来处理。为了正确覆盖响应的MIME类型,必需在调用send()之前调用overrideMimeType().
JavaScript高级程序设计

以上内容来源与 JavaScript高级教程设计第四版 ,仅作为学习记录使用,如涉及版权相关问题请联系我

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值