mp-mini-axios
Version:
MiniAxios 是一个轻量级 HTTP 客户端库,专为【微信小程序】设计,提供类似 Axios 的 API 接口。它支持请求/响应拦截器、取消请求、自动重试、文件上传/下载等功能。构建后大小11KB,能有效节省小程序包大小。
492 lines (408 loc) • 12.8 kB
Markdown
# MiniAxios 使用文档
MiniAxios 是一个轻量级 HTTP 客户端库,专为【微信小程序】设计,提供类似 Axios 的 API 接口。它支持请求/响应拦截器、取消请求、自动重试、文件上传/下载等功能。构建后大小11KB,能有效节省小程序包大小。
## 关于模块名称与类名
最开始,打算把模块叫做mini-axios,发布...重名。改名为nano-axios,还得意洋洋写了句,nano < mirco < mini,发布...又重!又改名为mp-axios,又说和mp_axios太像,最终改为mp-mini-axios。由于开发的时候使用了MiniAxios作为类名,这里就不改了。
## 安装与引入
### 1. 使用模块
```
// 1. 安装模块
npm i mp-mini-axios;
// 2. 构建npm
微信开发者工具 > 工具 > 构建 npm
// 3. 项目引入
import axios, { MiniAxios, CancelToken, AbortController } from 'mp-mini-axios';
```
### 2. 复制源码到项目
将模块中的源码复制到小程序项目中:
- `src/index.js` - 导出文件
- `src/MiniAxios.js` - 核心库
- `src/CancelToken.js` - 取消令牌实现
- `src/AbortController.js` - 中止控制器实现
```javascript
import axios, { MiniAxios, CancelToken, AbortController } from './libs/miniAxios/index.js';
import axios, { MiniAxios } from './libs/miniAxios/MiniAxios.js';
import { CancelToken } from './libs/miniAxios/CancelToken.js';
import { AbortController } from './libs/miniAxios/AbortController.js';
```
## 创建实例
### 1. 使用默认实例
```javascript
// 使用默认配置
axios.get('/api/data')
.then(response => console.log(response.data))
.catch(error => console.error(error));
```
### 2. 使用工厂函数创建实例
```javascript
// 使用 create 方法创建实例
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: {
'X-Custom-Header': 'custom-value'
}
});
// 使用自定义实例
api.post('/users', { name: 'John' })
.then(response => console.log(response.data))
.catch(error => console.error(error));
```
### 3. 使用类创建实例
```javascript
// 创建自定义实例
const api = new MiniAxios({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: {
'X-Custom-Header': 'custom-value'
}
});
// 使用自定义实例
api.post('/users', { name: 'John' })
.then(response => console.log(response.data))
.catch(error => console.error(error));
```
## 配置项
MiniAxios 支持以下配置选项:
| 配置项 | 类型 | 默认值 | 说明 |
|--------|------|---------|------|
| `baseURL` | string | `''` | 基础 URL |
| `timeout` | number | `60000` | 请求超时时间(ms) |
| `headers`/`header` | object | `{}` | 请求头 |
| `retry` | boolean/number | `false` | 是否重试及重试次数 |
| `retryDelay` | number | `1000` | 重试延迟时间(ms) |
| `method` | string | `'get'` | 请求方法 |
| `params`/`query` | object | `{}` | URL 查询参数 |
| `data`/`body` | object | `{}` | 请求体数据 |
| `filePath` | string | `''` | 文件路径(上传/下载) |
| `name`/`fileName` | string | `'file'` | 文件字段名(上传) |
| `cancelToken` | CancelToken | `null` | 取消令牌 |
| `signal` | AbortSignal | `null` | 中止信号 |
| `onRetry` | function | `null` | 重试回调 |
| `onProgressUpdate` | function | `null` | 进度更新回调 |
| `onHeadersReceived` | function | `null` | 头部接收回调 |
| `enableCache` | boolean | `false` | 是否启用缓存 |
| `enableHttp2` | boolean | `false` | 是否启用 HTTP/2 |
| `enableQuic` | boolean | `false` | 是否启用 QUIC |
## 请求方法
### 1. 基本请求方法
```javascript
// GET 请求
axios.get('/api/data', {
params: { id: 123 }
}).then(response => console.log(response.data));
// POST 请求
axios.post('/api/users', {
name: 'John',
age: 30
}).then(response => console.log('创建成功'));
// PUT 请求
axios.put('/api/users/123', {
name: 'John Updated'
}).then(response => console.log('更新成功'));
// DELETE 请求
axios.delete('/api/users/123')
.then(response => console.log('删除成功'));
// HEAD 请求
axios.head('/api/data')
.then(response => console.log(response.headers));
// OPTIONS 请求
axios.options('/api/data')
.then(response => console.log(response.headers));
```
### 2. 通用请求方法
```javascript
axios.request({
url: '/api/data',
method: 'post',
data: { key: 'value' },
headers: {
'Content-Type': 'application/json'
}
}).then(response => console.log(response.data));
```
## 文件上传与下载
### 1. 文件上传
```javascript
// uploadFile(config)
// uploadFile(url, config)
// uploadFile(url, formData, config)
axios.uploadFile('/upload', {
description: '用户头像'
otherFormData: 'xxx',
}, {
filePath: '/path/to/avatar.jpg',
name: 'avatar', // 可选,默认 'file'
onProgressUpdate: progress => {
console.log(`上传进度: ${progress.progress}%`);
}
}).then(response => {
console.log('上传成功', response.data);
}).catch(error => {
console.error('上传失败', error);
});
```
### 2. 文件下载
```javascript
// downloadFile(config)
// downloadFile(url, config)
axios.downloadFile('/file.pdf', {
filePath: '/path/to/save.pdf',
onProgressUpdate: progress => {
console.log(`下载进度: ${progress.progress}%`);
}
}).then(response => {
console.log('下载成功', response.data.tempFilePath);
}).catch(error => {
console.error('下载失败', error);
});
```
## 拦截器
### 1. 请求拦截器
```javascript
// 添加请求拦截器
axios.interceptors.request.use(config => {
// 添加认证令牌
config.headers.Authorization = 'Bearer token';
// 记录请求日志
console.log('发送请求:', config.url);
return config;
}, error => {
// 处理请求错误
return Promise.reject(error);
});
```
### 2. 响应拦截器
```javascript
// 添加响应拦截器
axios.interceptors.response.use(response => {
// 处理响应数据
console.log('收到响应:', response.status);
// 只返回数据部分
return response.data;
}, error => {
// 处理响应错误
if (error.response && error.response.status === 401) {
// 处理未授权错误
console.log('未授权,跳转到登录页');
}
return Promise.reject(error);
});
```
### 3. 移除拦截器
```javascript
// 添加拦截器
const interceptorId = axios.interceptors.request.use(/* ... */);
// 移除拦截器
axios.interceptors.request.eject(interceptorId);
```
## 取消请求
### 1. 使用 CancelToken
```javascript
// 创建取消令牌
const source = CancelToken.source();
// 发起请求
axios.get('/api/data', {
cancelToken: source.token
}).catch(error => {
if (MiniAxios.isCancel(error)) {
console.log('请求已取消:', error.message);
}
});
// 取消请求
source.cancel('用户取消了请求');
```
### 2. 使用 AbortController
```javascript
// 创建中止控制器
const controller = new AbortController();
// 发起请求
axios.get('/api/data', {
signal: controller.signal
}).catch(error => {
if (error.code === 'ECONNABORTED') {
console.log('请求已中止:', error.message);
}
});
// 中止请求
controller.abort('用户中止了请求');
```
## 错误处理
### 1. 错误对象结构
错误对象包含以下属性:
```javascript
{
message: '错误消息',
code: '错误代码',
config: '请求配置',
request: '请求对象',
response: '响应对象(如果有)',
status: 'HTTP状态码',
retryCount: '重试次数(如果有)'
}
```
### 2. 常见错误代码
| 错误代码 | 说明 |
|----------|------|
| `ETIMEDOUT` | 请求超时 |
| `ECONNABORTED` | 请求被中止 |
| `ERR_BAD_REQUEST` | 客户端错误(4xx) |
| `ERR_BAD_RESPONSE` | 服务器错误(5xx) |
| `WX_API_ERROR` | 微信API错误 |
### 3. 错误处理示例
```javascript
axios.get('/api/data')
.then(response => console.log(response.data))
.catch(error => {
if (error.code === 'ETIMEDOUT') {
console.log('请求超时');
} else if (error.code === 'ECONNABORTED') {
console.log('请求被中止');
} else if (error.response) {
console.log(`服务器错误: ${error.response.status}`);
} else {
console.log('未知错误', error);
}
});
```
## 重试机制
### 1. 基本重试配置
```javascript
axios.get('/api/data', {
retry: 3, // 重试3次
retryDelay: 2000, // 每次重试间隔2秒
onRetry: (retryInfo) => {
console.log(`重试 #${retryInfo.retryCount}, 错误: ${retryInfo.error.message}`);
}
}).then(response => {
console.log('最终响应:', response.data);
}).catch(error => {
console.log('最终失败:', error.message);
});
```
### 2. 指数退避策略
MiniAxios 默认使用指数退避策略:
- 第一次重试延迟: `retryDelay`
- 第二次重试延迟: `retryDelay * 2`
- 第三次重试延迟: `retryDelay * 4`
- 以此类推
## 完整配置示例
```javascript
// 创建自定义实例
const api = new MiniAxios({
baseURL: 'https://api.example.com',
timeout: 15000,
headers: {
'X-Client': 'MiniApp'
},
retry: 2,
retryDelay: 1000
});
// 添加拦截器
api.interceptors.request.use(config => {
config.headers.Authorization = 'Bearer token';
return config;
});
api.interceptors.response.use(response => {
return response.data;
}, error => {
return Promise.reject(error);
});
// 发起请求
api.post('/users', {
name: 'John',
email: 'john@example.com'
}, {
onProgressUpdate: progress => {
console.log(`请求进度: ${progress.progress}%`);
}
}).then(data => {
console.log('用户创建成功', data);
}).catch(error => {
console.error('创建用户失败', error);
});
```
## 注意事项
1. **小程序限制**:
- 文件上传需使用 `wx.uploadFile`
- 文件下载需使用 `wx.downloadFile`
- 部分 API 在小程序中有特殊限制
2. **取消请求**:
- 小程序中取消请求使用 `requestTask.abort()`
- 取消后请求会立即失败
3. **错误处理**:
- 使用自定义错误类
- 错误对象中包含微信原生错误信息
4. **重试机制**:
- 默认只对非取消错误重试
- 可自定义重试条件和重试策略
5. **性能优化**:
- 避免在拦截器中执行耗时操作
- 合理设置超时时间
- 按需使用重试机制
## 最佳实践
1. **封装 API 模块**:
```javascript
// api.js
import axios from 'mp-mini-axios';
const api = axios.create({
baseURL: 'https://api.example.com'
});
export default {
getUsers: () => api.get('/users'),
createUser: (userData) => api.post('/users', userData),
uploadAvatar: (filePath, data) => api.uploadFile('/upload/avatar', data, { filePath })
};
```
2. **统一错误处理**:
```javascript
// 全局错误处理
api.interceptors.response.use(null, error => {
if (error.response && error.response.status === 401) {
// 跳转到登录页
wx.redirectTo({ url: '/pages/login' });
}
return Promise.reject(error);
});
```
3. **请求取消封装**:
```javascript
// 封装可取消请求
function makeCancelableRequest(request) {
const source = CancelToken.source();
const requestPromise = request(source.token);
return {
promise: requestPromise,
cancel: (message) => source.cancel(message || '请求已取消')
};
}
// 使用
const { promise, cancel } = makeCancelableRequest(
token => api.get('/data', { cancelToken: token })
);
// 取消请求
cancel();
```
4. **上传/下载进度显示**:
```javascript
// 上传文件显示进度
api.uploadFile('/upload', {}, {
filePath: '/path/to/file',
onProgressUpdate: progress => {
wx.showToast({
title: `上传中 ${progress.progress}%`,
icon: 'none'
});
}
});
```
## 总结
MiniAxios 为微信小程序提供了强大的 HTTP 客户端功能,主要特点包括:
1. **类 Axios API**:熟悉的 API 设计,降低学习成本
2. **请求/响应拦截器**:灵活处理请求和响应
3. **取消请求**:支持 CancelToken 和 AbortController 两种方式
4. **自动重试**:内置指数退避重试策略
5. **文件支持**:简化文件上传/下载操作
6. **错误处理**:统一错误处理机制
7. **配置灵活**:支持全局配置和请求级配置
通过合理使用 MiniAxios,可以大大简化小程序中的网络请求处理,提高开发效率和代码质量。