JavaScript学习教程,从入门到精通,XMLHttpRequest 与 Ajax 请求详解(25)
XMLHttpRequest 与 Ajax 请求详解
一、XMLHttpRequest 概述
XMLHttpRequest (XHR) 是一个 JavaScript API,用于在浏览器和服务器之间传输数据,而无需刷新页面。它是实现 Ajax (Asynchronous JavaScript and XML) 技术的核心。
主要特点:
- 异步通信:可以在后台发送和接收数据
- 支持多种数据格式:XML, JSON, HTML, 纯文本等
- 支持各种 HTTP 方法:GET, POST, PUT, DELETE 等
- 可以设置请求头和读取响应头
二、Ajax 请求流程
- 创建 XMLHttpRequest 对象
- 配置请求参数(方法、URL、是否异步等)
- 设置请求头(可选)
- 设置响应处理函数
- 发送请求
- 处理响应数据
三、常用 HTTP 请求方式
方法 | 描述 |
---|---|
GET | 请求指定的资源,通常用于获取数据 |
POST | 向指定资源提交数据进行处理,通常用于创建或更新资源 |
PUT | 替换指定资源的所有当前表示,通常用于完整更新 |
DELETE | 删除指定的资源 |
PATCH | 对资源进行部分修改 |
HEAD | 类似于 GET,但只返回头部信息,不返回实际内容 |
OPTIONS | 返回服务器支持的 HTTP 方法,用于跨域请求预检 |
四、接收响应数据
XHR 对象提供了多个属性和方法来处理响应:
responseText
: 获取字符串形式的响应数据responseXML
: 获取 XML 形式的响应数据(如果响应是 XML)status
: HTTP 状态码(如 200, 404 等)statusText
: HTTP 状态文本(如 “OK”, “Not Found” 等)readyState
: 请求状态(0-4)onreadystatechange
: 状态改变时触发的事件处理函数
五、HTTP 请求头
HTTP 请求头允许客户端向服务器传递附加信息。常用的请求头包括:
Content-Type
: 请求体的 MIME 类型(如application/json
)Accept
: 客户端能够接收的内容类型Authorization
: 认证信息(如 Bearer token)User-Agent
: 客户端信息Cache-Control
: 缓存控制X-Requested-With
: 标识 Ajax 请求(通常为XMLHttpRequest
)
六、代码示例
1. 基础 GET 请求示例
// 1. 创建XHR对象
const xhr = new XMLHttpRequest();// 2. 配置请求
xhr.open('GET', 'https://api.example.com/users', true); // 异步请求// 3. 设置响应处理函数
xhr.onreadystatechange = function() {if (xhr.readyState === 4) { // 请求完成if (xhr.status === 200) { // 成功响应console.log('响应数据:', xhr.responseText);const users = JSON.parse(xhr.responseText); // 解析JSON数据console.log('用户列表:', users);} else {console.error('请求失败:', xhr.status, xhr.statusText);}}
};// 4. 发送请求
xhr.send();
2. POST 请求示例(发送 JSON 数据)
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.example.com/users', true);// 设置请求头,告诉服务器发送的是JSON数据
xhr.setRequestHeader('Content-Type', 'application/json');xhr.onreadystatechange = function() {if (xhr.readyState === 4) {if (xhr.status === 201) { // 201表示资源创建成功console.log('用户创建成功:', xhr.responseText);} else {console.error('创建用户失败:', xhr.status, xhr.statusText);}}
};const newUser = {name: 'John Doe',email: 'john@example.com',age: 30
};// 发送JSON字符串
xhr.send(JSON.stringify(newUser));
3. 带自定义请求头的请求示例
// 创建XHR对象
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/user/profile', true);// 设置标准请求头
xhr.setRequestHeader('Accept', 'application/json');// 设置自定义请求头
xhr.setRequestHeader('X-Custom-Header', 'custom-value');
xhr.setRequestHeader('X-User-Token', 'abc123xyz');xhr.onreadystatechange = function() {if (xhr.readyState === 4) {if (xhr.status === 200) {const profile = JSON.parse(xhr.responseText);console.log('用户信息:', profile);// 读取响应头const contentType = xhr.getResponseHeader('Content-Type');console.log('内容类型:', contentType);// 获取所有响应头const allHeaders = xhr.getAllResponseHeaders();console.log('所有响应头:', allHeaders);} else {console.error('获取用户信息失败:', xhr.status, xhr.statusText);}}
};xhr.send();
4. 错误处理示例
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/products', true);// 超时设置(毫秒)
xhr.timeout = 5000; // 5秒超时// 超时处理
xhr.ontimeout = function() {console.error('请求超时');
};// 网络错误处理
xhr.onerror = function() {console.error('网络错误');
};xhr.onreadystatechange = function() {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300) {// 成功响应console.log('产品列表:', JSON.parse(xhr.responseText));} else if (xhr.status === 401) {console.error('未授权,请登录');} else if (xhr.status === 404) {console.error('资源不存在');} else if (xhr.status >= 500) {console.error('服务器错误');} else {console.error('请求失败:', xhr.status, xhr.statusText);}}
};xhr.send();
5. 文件上传示例(带进度监控)
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.example.com/upload', true);// 进度事件处理
xhr.upload.onprogress = function(event) {if (event.lengthComputable) {const percentComplete = (event.loaded / event.total) * 100;console.log('上传进度:', percentComplete.toFixed(2) + '%');}
};xhr.onload = function() {if (xhr.status === 200) {console.log('文件上传成功:', xhr.responseText);} else {console.error('文件上传失败:', xhr.status, xhr.statusText);}
};xhr.onerror = function() {console.error('上传过程中发生网络错误');
};const formData = new FormData();
const fileInput = document.querySelector('input[type="file"]');
formData.append('file', fileInput.files[0]);
formData.append('description', '这是一个文件描述');xhr.send(formData);
七、XMLHttpRequest readyState 状态
值 | 状态 | 描述 |
---|---|---|
0 | UNSENT | 代理被创建,但尚未调用 open() 方法 |
1 | OPENED | open() 方法已经被调用 |
2 | HEADERS_RECEIVED | send() 方法已经被调用,并且头部和状态已经可获得 |
3 | LOADING | 下载中;responseText 属性已经包含部分数据 |
4 | DONE | 下载操作已完成(可能是成功,也可能是失败,需检查status状态码) |
八、注意事项
-
跨域请求:默认情况下,XHR 遵循同源策略。如需跨域,服务器需要设置 CORS 头或使用 JSONP(仅限 GET)
-
同步请求:应避免使用同步请求(open 方法的第三个参数设为 false),因为它会阻塞 UI 线程
-
安全性:
- 不要使用 XHR 发送敏感数据,除非使用 HTTPS
- 验证所有来自服务器的数据,防止 XSS 攻击
-
性能:
- 复用 XHR 对象可以减少内存消耗
- 对于大量数据,考虑使用分页或流式传输
-
现代替代方案:虽然 XHR 仍然可用,但现代开发中更推荐使用 Fetch API 或 axios 等库