Ajax学习笔记:封装XHR

尝试像jQuery ajax一样封装XMLHttpRequest

来源:XMLHttpRequest—必知必会

一个稍微完整一点的http请求

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
let xhr = new XMLHttpRequest();
// 请求成功回调函数
xhr.onload = e => {
console.log('request success');
};
// 请求结束
xhr.onloadend = e => {
console.log('request loadend');
};
// 请求出错
xhr.onerror = e => {
console.log('request error');
};
// 请求超时
xhr.ontimeout = e => {
console.log('request timeout');
};
// 请求回调函数.XMLHttpRequest标准又分为Level 1和Level 2,这是Level 1和的回调处理方式
// xhr.onreadystatechange = () => {
// if (xhr.readyState !== 4) {
// return;
// }
// const status = xhr.status;
// if ((status >= 200 && status < 300) || status === 304) {
// console.log('request success');
// } else {
// console.log('request error');
// }
// };

xhr.timeout = 0; // 设置超时时间,0表示永不超时
// 初始化请求
xhr.open('GET/POST/DELETE/...', '/url', true || false);
// 设置期望的返回数据类型 'json' 'text' 'document' ...
xhr.responseType = '';
// 设置请求头
xhr.setRequestHeader('', '');
// 发送请求
xhr.send(null || new FormData || 'a=1&b=2' || 'json字符串');

封装XMLHttpRequest

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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
const http = {
/**
* js封装ajax请求
* >>使用new XMLHttpRequest 创建请求对象,所以不考虑低端IE浏览器(IE6及以下不支持XMLHttpRequest)
* >>使用es6语法,如果需要在正式环境使用,则可以用babel转换为es5语法 https://babeljs.cn/docs/setup/#installation
* @param settings 请求参数模仿jQuery ajax
* 调用该方法,data参数需要和请求头Content-Type对应
* Content-Type data 描述
* application/x-www-form-urlencoded 'name=哈哈&age=12'或{name:'哈哈',age:12} 查询字符串,用&分割
* application/json name=哈哈&age=12' json字符串
* multipart/form-data new FormData() FormData对象,当为FormData类型,不要手动设置Content-Type
* 注意:请求参数如果包含日期类型.是否能请求成功需要后台接口配合
*/
ajax: (settings = {}) => {
// 初始化请求参数
let _s = Object.assign({
url: '', // string
type: 'GET', // string 'GET' 'POST' 'DELETE'
dataType: 'json', // string 期望的返回数据类型:'json' 'text' 'document' ...
async: true, // boolean true:异步请求 false:同步请求 required
data: null, // any 请求参数,data需要和请求头Content-Type对应
headers: {}, // object 请求头
timeout: 1000, // string 超时时间:0表示不设置超时
beforeSend: (xhr) => {
},
success: (result, status, xhr) => {
},
error: (xhr, status, error) => {
},
complete: (xhr, status) => {
}
}, settings);

// 参数验证
if (!_s.url || !_s.type || !_s.dataType || !_s.async) {
alert('参数有误');
return;
}

// 创建XMLHttpRequest请求对象
let xhr = new XMLHttpRequest();

// 请求开始回调函数
xhr.addEventListener('loadstart', e => {
_s.beforeSend(xhr);
});
// 请求成功回调函数
xhr.addEventListener('load', e => {
const status = xhr.status;
if ((status >= 200 && status < 300) || status === 304) {
let result;
if (xhr.responseType === 'text') {
result = xhr.responseText;
} else if (xhr.responseType === 'document') {
result = xhr.responseXML;
} else {
result = xhr.response;
}
// 注意:状态码200表示请求发送/接受成功,不表示业务处理成功
_s.success(result, status, xhr);
} else {
_s.error(xhr, status, e);
}
});
// 请求结束
xhr.addEventListener('loadend', e => {
_s.complete(xhr, xhr.status);
});
// 请求出错
xhr.addEventListener('error', e => {
_s.error(xhr, xhr.status, e);
});
// 请求超时
xhr.addEventListener('timeout', e => {
_s.error(xhr, 408, e);
});
let useUrlParam = false;
let sType = _s.type.toUpperCase();
// 如果是"简单"请求,则把data参数组装在url上
if (sType === 'GET' || sType === 'DELETE') {
useUrlParam = true;
_s.url += http.getUrlParam(_s.url, _s.data);
}
// 初始化请求
xhr.open(_s.type, _s.url, _s.async);
// 设置期望的返回数据类型
xhr.responseType = _s.dataType;
// 设置请求头
for (const key of Object.keys(_s.headers)) {
xhr.setRequestHeader(key, _s.headers[key]);
}
// 设置超时时间
if (_s.async && _s.timeout) {
xhr.timeout = _s.timeout;
}
// 发送请求.如果是简单请求,请求参数应为null.否则,请求参数类型需要和请求头Content-Type对应
xhr.send(useUrlParam ? null : http.getQueryData(_s.data));
},
// 把参数data转为url查询参数
getUrlParam: (url, data) => {
if (!data) {
return '';
}
let paramsStr = data instanceof Object ? http.getQueryString(data) : data;
return (url.indexOf('?') !== -1) ? paramsStr : '?' + paramsStr;
},
// 获取ajax请求参数
getQueryData: (data) => {
if (!data) {
return null;
}
if (typeof data === 'string') {
return data;
}
if (data instanceof FormData) {
return data;
}
return http.getQueryString(data);
},
// 把对象转为查询字符串
getQueryString: (data) => {
let paramsArr = [];
if (data instanceof Object) {
Object.keys(data).forEach(key => {
let val = data[key];
// todo 参数Date类型需要根据后台api酌情处理
if (val instanceof Date) {
// val = dateFormat(val, 'yyyy-MM-dd hh:mm:ss');
}
paramsArr.push(encodeURIComponent(key) + '=' + encodeURIComponent(val));
});
}
return paramsArr.join('&');
}
}