XMLHttpRequest 详解

XMLHttpRequest(XHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest 在 ajax 编程中被大量使用。

方法

XMLHttpRequest.open()

初始化一个请求,其有三个参数:

1
2
3
4
5
XMLHttpRequest.open(method, url, async)

// method:请求方法,如 post get delete 等
// url:请求路径
// async:是否异步,默认为 true
XMLHttpRequest.send()

发送数据,数据格式为 json 或者 FormData 对象。如果请求是异步的,那么该方法将在请求发送后立即返回。

XMLHttpRequest.setRequestHeader()

设置 HTTP 请求头的值,每次调用只能添加一个请求头,可以多次调用。必须在 open() 方法之后、send() 方法之前调用。

其有两个参数,第一个为键,第二个为值。


属性

XMLHttpRequest.readyState

返回 一个数字,范围是 0-4,代表请求的状态码。

  • 0:XMLHttpRequest 对象创建之后,open() 方法调用之前
  • 1:open() 方法调用之后,send() 方法调用之前
  • 2:send() 方法被调用,并且头部和状态已经可获得
  • 3:下载中; responseText 属性已经包含部分数据。
  • 4:请求操作已完成。
XMLHttpRequest.response

包含整个响应实体。

XMLHttpRequest.responseText

服务端返回的数据。

XMLHttpRequest.responseURL

返回经过序列化的响应 URL,如果该 URL 为空,则返回空字符串。

XMLHttpRequest.status

返回请求的响应状态,如 200 400 500 等。

XMLHttpRequest.onreadyStatechange

该属性是一个函数,当 readyState 属性发生变化时调用,定义在 open() 方法之前。


事件

XMLHttpRequest.onloadstart

请求刚开始时触发。

XMLHttpRequest.onprogress

数据传输进行时触发。

XMLHttpRequest.onabort

上传操作终止时触发。

XMLHttpRequest.onerror

上传失败时触发。

XMLHttpRequest.onload

上传成功时触发。

XMLHttpRequest.onloadend

上传完成时触发。

注意:对于下载,可在 XMLHttpRequest.onprogress 上做监听。对于上传,可在 XMLHttpRequest.upload.onprogress 上做监听。


实践

上传文件并显示进度以及上传速度,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<body>
<input type="file" style="display: none;" id="fileInput">
<div>
<button onclick="uploadFiles()">点击上传</button>
<span id="filename"></span>
<span id="loading" style="display: none;">上传中...</span>
<span id="progress" style="display: none;"></span>
<span id="speed" style="display: none;"></span>
</div>

<script>
function uploadFiles() {
document.getElementById("fileInput").click();
document.getElementById("fileInput").addEventListener('change', function(event) {
var file = event.currentTarget.files[0];
const file_name = file.name;
var formData = new FormData();

document.getElementById('filename').innerHTML = file_name;
formData.append("file", file);

var xhr = new XMLHttpRequest();
var currentLoaded;
var startTime;

xhr.onreadystatechange = function() {
if(this.readyState == 1) {
document.getElementById('loading').style.display = 'inline-block';
document.getElementById('progress').style.display = 'inline-block';
}
if(this.readyState == 2) {
document.getElementById('loading').innerHTML = '上传成功';
document.getElementById('progress').style.display = 'none';
document.getElementById('speed').style.display = 'none';
}
if(this.readyState == 4) {
console.log(this.responseText);
}
}

// 上传刚开始时调用
xhr.onloadstart = function() {
startTime = new Date().getTime();
currentLoaded = 0;
}

// 监听上传过程
xhr.onprogress = function(ev) {
if (ev.lengthComputable) {
// 计算进度
var percent = Math.round(ev.loaded * 100 / ev.total);
document.getElementById('progress').innerHTML = percent + '%';

var endTime = new Date().getTime();
var dtime = (endTime - startTime) / 1000;
var dloaded = ev.loaded - currentLoaded;
startTime = new Date().getTime();
currentLoaded = ev.loaded;
var speed = dloaded / dtime;
var unit = 'b/s';
if(speed/1024 > 1) {
unit = 'Kb/s';
speed /= 1024;
if(speed/1024 > 1) {
unit = 'Mb/s';
speed /= 1024;
}
}
document.getElementById('speed').style.display = 'inline-block';
document.getElementById('speed').innerHTML = speed.toFixed(2) + ' ' + unit;
}
else {
document.getElementById('progress').innerHTML = '无法计算';
}
}
xhr.open('post', 'xxxxxxx');
xhr.setRequestHeader('accept', 'application/json');
xhr.send(formData);
})
}
</script>
</body>