XMLHttpRequest(XHR)作为浏览器原生API,其设计体现了Web开发中异步通信的核心需求。2005年AJAX技术兴起后,XHR彻底改变了前端开发模式,使网页从静态文档进化为动态应用。其底层实现基于浏览器引擎的HTTP协议栈,通过JavaScript接口暴露给开发者。
XHR的核心优势在于:
重要提示:虽然Fetch API已成为现代标准,但XHR在兼容性要求高的场景仍是必备技能。截至2023年,仍有15%的网站直接使用XHR(数据来源:WebAlmanac)
现代浏览器创建XHR对象的标准方式:
javascript复制const xhr = new XMLHttpRequest();
但实际生产环境中需要考虑IE兼容:
javascript复制let xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest(); // 现代浏览器
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP"); // IE5/6
}
javascript复制xhr.open('POST', '/api/submit', true);
参数说明:
method:HTTP方法(GET/POST/PUT/DELETE等)url:请求地址(相对/绝对路径)async:默认为true,设为false会导致UI阻塞(已废弃)user/password:基本认证凭据(实际开发建议使用Token)javascript复制// GET请求
xhr.send();
// POST请求
xhr.send(JSON.stringify({key: 'value'}));
注意事项:
| 属性 | 类型 | 说明 |
|---|---|---|
| readyState | Number | 0-4状态值(UNSENT→DONE) |
| status | Number | HTTP状态码(200/404等) |
| responseType | String | 指定响应格式(json/blob等) |
| timeout | Number | 超时时间(毫秒) |
| withCredentials | Boolean | 是否发送凭据(跨域请求) |
javascript复制const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/data');
xhr.responseType = 'json';
xhr.onload = function() {
if (xhr.status === 200) {
console.log(xhr.response);
} else {
console.error('Request failed:', xhr.statusText);
}
};
xhr.onerror = function() {
console.error('Network error occurred');
};
xhr.send();
javascript复制xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
const percent = (e.loaded / e.total) * 100;
console.log(`上传进度: ${percent.toFixed(2)}%`);
}
};
xhr.onprogress = function(e) {
// 下载进度监控
};
javascript复制xhr.timeout = 5000; // 5秒超时
xhr.ontimeout = function() {
console.warn('请求超时');
};
// 手动中止
document.getElementById('cancelBtn').addEventListener('click', () => {
xhr.abort();
});
javascript复制function fetchWithRetry(url, retries = 3) {
return new Promise((resolve, reject) => {
function attempt() {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = () => resolve(xhr.response);
xhr.onerror = () => {
if (retries > 0) {
retries--;
attempt();
} else {
reject(new Error('Max retries exceeded'));
}
};
xhr.send();
}
attempt();
});
}
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
| 跨域请求失败 | 未配置CORS | 服务端设置Access-Control-Allow-Origin |
| 状态码0 | 请求被取消或跨域限制 | 检查网络连接和CORS配置 |
| 解析JSON失败 | 未设置responseType | 设置xhr.responseType = 'json' |
| 上传卡住 | 文件过大未分片 | 实现分片上传或使用WebSocket |
javascript复制['loadstart', 'progress', 'abort', 'error', 'load', 'timeout']
.forEach(event => {
xhr.addEventListener(event, console.log);
});
虽然Fetch API和axios等库提供了更现代的接口,但在以下场景仍需使用XHR:
迁移到Fetch API的示例:
javascript复制// XHR
xhr.open('GET', '/api/data');
xhr.send();
// Fetch等效实现
fetch('/api/data')
.then(response => response.json())
.then(data => console.log(data));
在实际项目中,我通常会根据目标浏览器支持度决定技术选型。对于需要精细控制请求过程的场景,XHR仍然是不可替代的工具。特别是在处理大文件上传时,XHR的progress事件比Fetch API更加可靠和精确。