基于微信小程序的wx.request()方法封装
下面是一个封装方案,满足您提出的所有要求:
class HttpService {
constructor() {
this.baseUrl = ''; // 基础URL
this.pendingRequests = new Map(); // 请求缓存池
this.interceptors = {
request: [],
response: []
};
}
// 设置基础URL
setBaseUrl(url) {
this.baseUrl = url;
}
// 添加拦截器
useInterceptor(type, handler) {
if (this.interceptors[type]) {
this.interceptors[type].push(handler);
}
}
// 核心请求方法
async request(config) {
const {
url,
method = 'GET',
data = {},
header = {},
showLoading = false
} = config;
// 生成请求唯一标识
const requestKey = `${method}_${url}_${JSON.stringify(data)}`;
// 检查重复请求
if (this.pendingRequests.has(requestKey)) {
return this.pendingRequests.get(requestKey);
}
// 请求前拦截处理
let finalConfig = { url, method, data, header, showLoading };
for (const interceptor of this.interceptors.request) {
finalConfig = await interceptor(finalConfig) || finalConfig;
}
// 创建请求Promise
const requestPromise = new Promise((resolve, reject) => {
// 显示加载状态
if (finalConfig.showLoading) {
wx.showLoading({ title: '加载中', mask: true });
}
wx.request({
url: this.baseUrl + finalConfig.url,
method: finalConfig.method,
data: finalConfig.data,
header: finalConfig.header,
success: async (res) => {
// 响应后拦截处理
let processedRes = res;
for (const interceptor of this.interceptors.response) {
processedRes = await interceptor(processedRes) || processedRes;
}
resolve(processedRes);
},
fail: (err) => {
// 错误处理拦截
let processedErr = err;
for (const interceptor of this.interceptors.response) {
processedErr = interceptor(processedErr) || processedErr;
}
reject(processedErr);
},
complete: () => {
// 隐藏加载状态
if (finalConfig.showLoading) {
wx.hideLoading();
}
// 从缓存池移除
this.pendingRequests.delete(requestKey);
}
});
});
// 缓存当前请求
this.pendingRequests.set(requestKey, requestPromise);
return requestPromise;
}
// 并发请求处理
all(requests) {
return Promise.all(requests);
}
// 快捷方法:GET
get(url, params = {}, config = {}) {
return this.request({
...config,
url,
method: 'GET',
data: params
});
}
// 快捷方法:POST
post(url, data = {}, config = {}) {
return this.request({
...config,
url,
method: 'POST',
data
});
}
// 快捷方法:PUT
put(url, data = {}, config = {}) {
return this.request({
...config,
url,
method: 'PUT',
data
});
}
// 快捷方法:DELETE
delete(url, params = {}, config = {}) {
return this.request({
...config,
url,
method: 'DELETE',
data: params
});
}
}
// 创建实例
const http = new HttpService();
// 设置基础URL(示例)
http.setBaseUrl('https://api.example.com');
// 添加请求拦截器(示例:添加token)
http.useInterceptor('request', (config) => {
const token = wx.getStorageSync('token');
if (token) {
config.header = {
...config.header,
Authorization: `Bearer ${token}`
};
}
return config;
});
// 添加响应拦截器(示例:错误处理)
http.useInterceptor('response', (response) => {
if (response.statusCode !== 200) {
wx.showToast({
title: `请求错误: ${response.data.message || '未知错误'}`,
icon: 'none'
});
throw new Error('请求失败');
}
return response.data;
});
功能说明
加载状态控制
- 通过
showLoading
参数控制是否显示加载动画 - 默认不显示,需要时手动开启
- 使用微信原生
showLoading/hideLoading
方法
- 通过
拦截器系统
- 请求拦截器:在请求发送前修改配置
- 响应拦截器:处理响应数据和错误
- 支持添加多个拦截器,按添加顺序执行
并发请求处理
all()
方法处理多个并发请求- 内部使用
Promise.all
实现 - 示例用法:
const [userData, productList] = await http.all([ http.get('/user'), http.get('/products') ]);
重复请求过滤
- 使用请求方法+URL+参数的哈希值作为唯一标识
- 相同请求返回缓存中的Promise对象
- 避免网络资源浪费
快捷方法
- 内置GET/POST/PUT/DELETE快捷方法
- 简化常用请求调用
- 示例:
// GET请求 const data = await http.get('/api/data', { page: 1 }); // POST请求 await http.post('/api/submit', { name: 'John' }, { showLoading: true });
使用示例
// 获取用户信息
async function fetchUser() {
try {
const user = await http.get('/user/profile', null, { showLoading: true });
console.log('用户数据:', user);
} catch (error) {
console.error('获取用户信息失败', error);
}
}
// 提交表单数据
async function submitForm(data) {
try {
const result = await http.post('/form/submit', data, {
showLoading: true,
header: { 'Content-Type': 'application/json' }
});
wx.showToast({ title: '提交成功' });
} catch (error) {
// 错误已在拦截器处理
}
}
// 并发请求示例
async function fetchAllData() {
try {
const [orders, messages] = await http.all([
http.get('/user/orders'),
http.get('/user/messages')
]);
console.log('订单数据:', orders);
console.log('消息数据:', messages);
} catch (error) {
console.error('数据获取失败', error);
}
}
这个封装方案具有以下优势:
- 完整的拦截器系统支持预处理和后处理
- 智能的请求缓存机制避免重复请求
- 简洁的API设计降低使用复杂度
- 完善的错误处理流程
- 灵活的加载状态控制
- TypeScript友好,可轻松添加类型定义