目录
AJAX(Asynchronous JavaScript and XML)核心原理:通过浏览器提供的 XMLHttpRequest(XHR)对象,实现异步通信,无需刷新页面即可与服务器交换数据。
一、XMLHttpRequest使用步骤
基本语法
- 创建对象 → 配置请求 → 监听事件 → 发送请求
const xhr = new XMLHttpRequest()
xhr.open('请求方法', '请求url网址')
xhr.addEventListener('loadend', () => {
// 响应结果
console.log(xhr.response)
})
xhr.send()
步骤 1:创建 XHR 对象
const xhr = new XMLHttpRequest();
作用:初始化一个 XHR 实例,用于后续的请求配置和操作。
注意:旧版 IE(< IE7)需使用
ActiveXObject
,但现代浏览器无需兼容处理。
步骤 2:调用 open()
方法
xhr.open(method, url, async);
参数说明:
method
:HTTP 方法(GET
、POST
、PUT
等)。url
:请求的目标地址(支持绝对或相对路径)。async
:是否异步(默认为true
,强烈建议使用异步)。
关键点:
GET 请求的查询参数需直接拼接到 URL 中(需手动编码)。
const params = { page: 1, keyword: 'AJAX' }; const query = new URLSearchParams(params).toString(); // 自动编码 const url = `https://api.example.com/data?${query}`; xhr.open('GET', url, true);
POST 请求的数据在
send()
中传递(需配合请求头)。
步骤 3:监听 loadend
事件
xhr.addEventListener('loadend', function() {
// 请求完成(无论成功或失败)
if (xhr.status >= 200 && xhr.status < 300) {
console.log('成功:', xhr.responseText);
} else {
console.error('失败:', xhr.status, xhr.statusText);
}
});
loadend
事件特性:在请求完成(包括成功、失败或取消)后触发。
替代传统
onreadystatechange
的繁琐状态判断。
响应数据获取:
xhr.responseText
:字符串形式的响应数据(如 JSON、HTML)。xhr.response
:根据responseType
自动转换后的数据(如 JSON 对象)。
步骤 4:调用 send()
方法
xhr.send(body);
GET 请求:
send()
无参数或传null
。xhr.send();
POST 请求:传递请求体数据(需设置
Content-Type
)。// 设置请求头(JSON 格式) xhr.setRequestHeader('Content-Type', 'application/json'); // 提交 JSON 数据 const postData = JSON.stringify({ username: 'john', age: 25 }); xhr.send(postData); // 提交 FormData(文件上传) const formData = new FormData(); formData.append('file', fileInput.files[0]); xhr.send(formData);
二、完整示例
1. GET 请求(带查询参数)
const xhr = new XMLHttpRequest();
// 构建带查询参数的 URL
const params = { page: 1, search: 'AJAX 教程' };
const url = `https://api.example.com/data?${new URLSearchParams(params)}`;
xhr.open('GET', url, true);
xhr.addEventListener('loadend', () => {
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
console.log('数据:', data);
} else {
console.error(`请求失败: ${xhr.status}`);
}
});
xhr.send();
2. POST 请求(提交 JSON 数据)
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.example.com/submit', true);
// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.addEventListener('loadend', () => {
if (xhr.status === 201) {
console.log('提交成功:', xhr.responseText);
} else {
console.error(`错误: ${xhr.status}`);
}
});
// 提交 JSON 数据
const data = { title: 'XHR 教程', content: '详细指南' };
xhr.send(JSON.stringify(data));
三、关键注意事项
查询参数编码:
// 手动编码示例 const keyword = '前端&后端'; const encodedKeyword = encodeURIComponent(keyword); // → '前端%26后端'
使用
URLSearchParams
或encodeURIComponent
避免特殊字符问题。
POST 请求头设置:
必须根据数据类型设置
Content-Type
,否则服务器无法正确解析。application/json
:JSON 数据。multipart/form-data
:文件上传。application/x-www-form-urlencoded
:表单数据。
错误处理:
结合
loadend
和xhr.status
处理 HTTP 状态码。监听
error
和timeout
事件处理网络错误和超时。xhr.addEventListener('error', () => { console.error('网络错误'); }); xhr.timeout = 5000; // 设置超时时间 xhr.addEventListener('timeout', () => { console.error('请求超时'); });
同步请求已废弃:
open()
的第三个参数若设为false
(同步请求),会导致页面阻塞,现代开发中禁止使用。
XHR和Axios的默认请求头对比
场景 | XHR(原生) | Axios |
---|---|---|
发送 JSON 数据 | 需手动设置 Content-Type |
自动设置 Content-Type: application/json |
发送 FormData | 自动设置 multipart/form-data |
自动设置 multipart/form-data |
全局默认头 | 无 | 支持通过 axios.defaults.headers 配置全局头 |
拦截器 | 无 | 支持请求/响应拦截器统一管理头 |
必须声明Headers的情况
场景 | XHR | Axios |
---|---|---|
发送非表单数据 | 必须手动设置 Content-Type |
自动处理,可手动覆盖 |
身份认证 | 必须设置 Authorization |
必须设置 Authorization |
跨域自定义头 | 必须声明且服务器允许 | 必须声明且服务器允许 |
文件上传 | 使用 FormData 时自动处理 |
使用 FormData 时自动处理 |
四、URLSearchParams
1. URLSearchParams
的作用
URLSearchParams
是一个 Web API,用于解析、操作 URL 的查询参数(即 ?
后的部分)。它可以:
将对象转换为 URL 查询字符串(自动编码特殊字符)。
解析现有查询字符串为键值对。
动态添加、删除、遍历参数。
2. 代码示例解析
qObj = { key1: 'value1', key2: 'value2' }
const paramsObj = new URLSearchParams(qObj);
const queryString = paramsObj.toString();
xhr.open('GET', `http://example.net/api?${queryString}`);
步骤分解:
创建
URLSearchParams
实例const paramsObj = new URLSearchParams(qObj);
假设
qObj
是一个对象(如{ key1: 'value1', key2: 'value2' }
)。URLSearchParams
会将其转换为键值对结构。
生成查询字符串
const queryString = paramsObj.toString();
toString()
方法将参数转换为标准的 URL 查询字符串(如key1=value1&key2=value2
)。自动处理编码:空格转为
%20
,中文转为%E4%B8%AD
等。
拼接完整 URL
xhr.open('GET', `http://example.net/api?${queryString}`);
最终生成的 URL 示例:
http://example.net/api?key1=value1&key2=value2
3. URLSearchParams
常用方法
1. 添加参数
paramsObj.append('page', 1); // 添加新参数
paramsObj.append('page', 2); // 允许重复键:page=1&page=2
2. 删除参数
paramsObj.delete('key1'); // 删除指定键
3. 获取参数值
const value = paramsObj.get('key1'); // 获取第一个值
const allValues = paramsObj.getAll('page'); // 获取所有值(数组)
4. 遍历参数
for (const [key, value] of paramsObj) {
console.log(key, value);
}
4. 处理特殊字符
URLSearchParams
会自动编码特殊字符,无需手动调用 encodeURIComponent
。
示例:
const params = new URLSearchParams({ city: '北京', q: 'a&b=c' });
console.log(params.toString());
// 输出:city=%E5%8C%97%E4%BA%AC&q=a%26b%3Dc
5. 可选链操作符
JavaScript 中的
?.
是可选链操作符(Optional Chaining Operator),用于安全地访问对象的深层属性。它的作用是:当某个中间属性为null
或undefined
时,直接返回undefined
,而不会抛出错误。
代码示例分析:
// 假设 xhr 是 XMLHttpRequest 的实例
const data = xhr.response?.data;
xhr.response
XHR 请求完成后,xhr.response
是服务器返回的数据。
如果请求未完成或失败,xhr.response
可能是null
或undefined
。xhr.response?.data
如果
xhr.response
存在:继续访问data
属性。如果
xhr.response
是null
或undefined
:直接返回undefined
,不会尝试访问.data
。
可选链操作符(?.
)的核心规则:
场景 | 代码示例 | 结果 |
---|---|---|
属性存在 | obj?.prop |
返回 obj.prop |
属性不存在(null/undefined ) |
obj?.prop |
返回 undefined ,不会报错 |
深层属性访问 | obj?.prop1?.prop2 |
逐层检查,任一中间属性为 null/undefined 则返回 undefined |
函数调用 | obj.method?.() |
如果 obj.method 存在则调用,否则返回 undefined |
五、简易封装axios
Axios 原理:基于
Promise
封装的 HTTP 客户端库,底层依赖XMLHttpRequest
(浏览器)或http
模块(Node.js),提供更简洁、强大的 API。
1. Axios 核心设计
适配器模式
浏览器环境:使用
XMLHttpRequest
发送请求。Node.js 环境:使用
http
模块发送请求。统一 API:开发者无需关注底层差异。
拦截器机制
请求拦截器:在请求发送前统一处理(如添加 Token)。
响应拦截器:在响应返回后统一处理(如错误过滤)。
// 添加请求拦截器 axios.interceptors.request.use(config => { config.headers.Authorization = 'Bearer token'; return config; }); // 添加响应拦截器 axios.interceptors.response.use( response => response.data, // 提取 data 字段 error => Promise.reject(error) );
配置合并策略
全局配置 → 实例配置 → 单次请求配置,优先级递增。
自动处理
headers
(如Content-Type
根据数据类型推断)。
Promise 链式调用
所有请求返回
Promise
对象,支持async/await
。错误通过
.catch()
或try/catch
统一处理。
2. 简易封装示例
模拟 axios 函数封装,更深入了解 axios 内部运作原理:
//定义myAxios函数,接收配置对象,返回Promise对象
function myAxios(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
//判断有params选项,携带查询参数
if (config.params) {
//使用URLSearchParams转换,并携带到url上
const paramsObj = new URLSearchParams(config.params)
const queryString = paramsObj.toString()
config.url += `?${queryString}`
}
//发起XHR请求,默认请求方法为GET
xhr.open(config.method || 'GET', config.url)
xhr.addEventListener('loadend', () => {
//调用成功/失败的处理程序
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
}
else {
reject(new Error(xhr.response))
}
})
//判断有data选项,携带请求体
if (config.data) {
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(JSON.stringify(config.data))
}
else {
xhr.send()
}
})
}
3. AJAX 与 Axios 对比
特性 | AJAX(原生 XHR) | Axios |
---|---|---|
底层实现 | 直接操作 XMLHttpRequest 对象 |
封装 XHR 或 Node.js http 模块,提供统一 API |
异步处理 | 回调函数 | 基于 Promise ,支持 async/await |
数据转换 | 手动解析 JSON、XML 等格式 | 自动转换 JSON 数据 |
拦截器 | 需手动实现 | 内置请求/响应拦截器 |
取消请求 | 使用 xhr.abort() |
支持 CancelToken 和 AbortController |
跨域处理 | 需服务端配合 CORS 或 JSONP | 自动处理 CORS,支持 withCredentials 配置 |
代码简洁性 | 冗余,需手动处理细节 | 链式调用,配置化 API |