计算机网络系列 -- XMLHttpRequest

375 阅读4分钟

前言

XMLHttpRequest是一个浏览器接口,使得Javascript可以进行HTTP(S)通信。

最早,微软在 IE5 引进了这个接口。因为它太有用,其他浏览器也模仿部署了,ajax操作因此得以诞生。

此接口前后有两个版本,我们分别看这两个版本:老版本、新版本

老版本的XMLHttpRequest对象

老版本的用法如下:

  1. 首先,新建一个 XMLHttpRequest 的实例
var xhr
= new XMLHttpRequest();
  1. 然后,向远程主机发出一个 HTTP 请求:(先打开后发送)
xhr.open('GET', 'example.php'); // xhr.open(请求方式 , 请求 URL(GET 方式传参))
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // 自定义头部字段
xhr.send(); // 发起请求,可传参(POST 方式传参)
  1. 接着,就等待远程主机做出回应。此时需要 监控 XMLHttpRequest 对象的状态变化,指定回调函数
xhr.onreadystatechange = function(){
    if ( xhr.readyState == 4 && xhr.status == 200 ) {
        alert( xhr.responseText );
    } else {
        alert( xhr.statusText );
    }
};

上面的代码包含了老版本 XMLHttpRequest 对象的主要属性:

  • xhr.readyState:XMLHttpRequest 对象的状态,等于 4 表示数据已经接收完毕
  • xhr.status:服务器返回的状态码,等于 200 表示一切正常。
  • xhr.responseText:服务器返回的文本数据
  • xhr.responseXML:服务器返回的 XML 格式的数据
  • xhr.statusText:服务器返回的状态文本

老版本的缺点

老版本的 XMLHttpRequest 对象有以下几个缺点:

  • 只支持文本数据的传送,无法用来读取和上传二进制文件
  • 传送和接收数据时,没有进度信息,只能提示有没有完成
  • 受到 "同源政策" 的影响 ,只能向同一域名的服务器请求数据

新版本的功能

新版本的 XMLHttpRequest 对象,针对老版本的缺点,做出了大幅改进:

  1. 可以设置 HTTP 请求的时限
  2. 可以使用 FormData 对象管理表单数据
  3. 可以上传文件
  4. 可以获得数据传输的进度信息
  5. 可以请求不同域名下的数据(跨域请求
  6. 可以获取服务器端的二进制数据。

1. HTTP 请求的时限

有时,ajax操作很耗时,而且无法预知要花多长时间。如果网速很慢,用户可能要等很久。

新版本的 XMLHttpRequest 对象,增加了 timeout 属性,可以设置 HTTP 请求的时限

xhr.timeout = 3000;

上面的语句,将最长等待时间设为 3000 毫秒。过了这个时限,就 自动停止 HTTP 请求。与之配套的还有 ontimeout 事件,用来指定回调函数

xhr.ontimeout = function(event){
    alert('请求超时!');
}

2. FormData 对象

ajax 操作往往用来传递表单数据。为了方便表单处理,HTML5新增了一个 FormData 对象,可以模拟表单

  1. 首先,新建一个 FormData 对象:
var formData = new FormData();
  1. 然后,为它添加表单项
formData.append('username', '张三');
formData.append('id', 123456);
  1. 最后,直接传送这个 FormData 对象。这与提交网页表单的效果,完全一样
xhr.send(formData);

FormData 对象也可以用来获取网页表单的值

var form = document.getElementById('myform');
var formData = new FormData(form);
formData.append('secret', '123456'); // 添加一个表单项
xhr.open('POST', form.action);
xhr.send(formData); // 发送该表单

3. 上传文件

新版XMLHttpRequest对象,不仅可以发送文本信息,还可以上传文件。

假定files是一个"选择文件"的表单元素(input[type="file"]),我们将它 装入 FormData 对象,然后发送这个 FormData 对象

var formData = new FormData();
for (var i = 0; i < files.length;i++) {
    formData.append('files[]', files[i]);
}
xhr.send(formData);

4. 获取进度信息

新版本的 XMLHttpRequest 对象,传送数据的时候,有一个 progress 事件,用来返回进度信息。

它分成上传和下载两种情况:

  • 下载 的 progress 事件属于 XMLHttpRequest 对象
  • 上传 的 progress 事件属于 XMLHttpRequest.upload 对象
  1. 先定义 progress 事件的回调函数
xhr.onprogress = updateProgress;
xhr.upload.onprogress = updateProgress;
  1. 然后,在回调函数里面,使用这个事件的一些属性
function updateProgress(event) {
    if (event.lengthComputable) {
        var percentComplete = event.loaded / event.total;
    }
}

上面的代码中:

  • event.total 是需要传输的总字节
  • event.loaded 是已经传输的字节
  • 如果 event.lengthComputable 不为真,则 event.total 等于 0

与 progress 事件相关的,还有其他五个事件,可以分别指定回调函数:

  • load 事件:传输成功完成
  • abort 事件:传输被用户取消
  • error 事件:传输中出现错误
  • loadstart 事件:传输开始
  • loadEnd 事件:传输结束,但是不知道成功还是失败

5. 跨域资源共享(CORS)

新版本的XMLHttpRequest对象,可以向不同域名的服务器发出HTTP请求。这叫做"跨域资源共享"(Cross-origin resource sharing,简称 CORS)。

使用"跨域资源共享"的前提:1. 浏览器必须支持这个功能,而且 2. 服务器端必须同意这种"跨域"。如果能够满足上面的条件,则代码的写法与不跨域的请求完全一样

xhr.open('GET', 'http://other.server/and/path/to/script');

更多关于 CORS 的内容见 浏览器系列 -- 跨域

参考文章