基于微信小程序的wx.request()方法封裝
下面是一個封裝方案,滿足您提出的所有要求:
class HttpService {constructor() {this.baseUrl = ''; // 基礎URLthis.pendingRequests = new Map(); // 請求緩存池this.interceptors = {request: [],response: []};}// 設置基礎URLsetBaseUrl(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;}// 創建請求Promiseconst 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);}// 快捷方法:GETget(url, params = {}, config = {}) {return this.request({...config,url,method: 'GET',data: params});}// 快捷方法:POSTpost(url, data = {}, config = {}) {return this.request({...config,url,method: 'POST',data});}// 快捷方法:PUTput(url, data = {}, config = {}) {return this.request({...config,url,method: 'PUT',data});}// 快捷方法:DELETEdelete(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友好,可輕松添加類型定義