一个ai生成的微信小程序请求类封装
一个ai生成的微信小程序请求类封装,里面加了防止一个请求多次同时请求,通过请求方法+URL+参数生成唯一key防止重复提交,
request.js
class Request { constructor(options = {}) { // 默认配置 this.defaults = { baseURL: '', timeout: 60000, header: { 'Content-Type': 'application/json' }, // 是否默认开启防重复请求 preventDuplicate: true, // 重复请求的提示信息 duplicateMessage: '请不要频繁操作' }; // 合并用户配置 this.defaults = { ...this.defaults, ...options }; // 请求队列,存储正在进行的请求标识 this.requestQueue = new Map(); // 拦截器 this.interceptors = { request: { use: (onFulfilled, onRejected) => { this.requestInterceptor = { onFulfilled, onRejected }; } }, response: { use: (onFulfilled, onRejected) => { this.responseInterceptor = { onFulfilled, onRejected }; } } }; } /** * 生成请求的唯一标识 * @param {Object} options 请求配置 * @returns {String} 请求标识 */ generateRequestKey(options) { const { url, method = 'GET', data = {} } = options; // 排序参数,确保不同顺序的相同参数生成相同的key const sortedData = Object.keys(data).sort().reduce((obj, key) => { obj[key] = data[key]; return obj; }, {}); // 组合baseURL、方法、URL和参数生成唯一标识 return `${this.defaults.baseURL}-${method.toUpperCase()}-${url}-${JSON.stringify(sortedData)}`; } /** * 加入请求队列 * @param {String} key 请求标识 * @returns {Boolean} 是否加入成功 */ addToQueue(key) { if (this.requestQueue.has(key)) { return false; } this.requestQueue.set(key, true); return true; } /** * 从请求队列移除 * @param {String} key 请求标识 */ removeFromQueue(key) { this.requestQueue.delete(key); } /** * 发起请求 * @param {Object} options 请求配置 * @returns {Promise} 请求Promise */ request(options) { // 合并默认配置和请求配置 const config = { ...this.defaults, ...options }; // 处理URL(拼接baseURL) const url = config.baseURL ? `${config.baseURL}${config.url}` : config.url; // 生成请求标识 const requestKey = this.generateRequestKey({ url: config.url, method: config.method, data: config.data }); // 检查是否需要防止重复请求 if (config.preventDuplicate) { if (!this.addToQueue(requestKey)) { // 重复请求,返回失败 const error = new Error(config.duplicateMessage); error.type = 'DUPLICATE_REQUEST'; return Promise.reject(error); } } // 包装请求选项 const requestOptions = { url, method: config.method || 'GET', data: config.data || {}, header: { ...config.header, ...options.header }, timeout: config.timeout }; // 执行请求拦截器 let interceptedOptions = { ...requestOptions }; if (this.requestInterceptor && this.requestInterceptor.onFulfilled) { try { interceptedOptions = this.requestInterceptor.onFulfilled(interceptedOptions); } catch (error) { // 拦截器出错,从队列移除并返回错误 if (config.preventDuplicate) { this.removeFromQueue(requestKey); } if (this.requestInterceptor.onRejected) { return Promise.reject(this.requestInterceptor.onRejected(error)); } return Promise.reject(error); } } // 创建请求Promise const requestPromise = new Promise((resolve, reject) => { // 记录开始时间用于超时判断 const startTime = Date.now(); // 发起微信原生请求 const task = wx.request({ ...interceptedOptions, success: (response) => { resolve(response); }, fail: (error) => { reject(error); }, complete: () => { // 无论成功失败,都从队列移除 if (config.preventDuplicate) { this.removeFromQueue(requestKey); } } }); // 处理超时(如果原生超时不生效时的备用方案) if (config.timeout) { const timeoutTimer = setTimeout(() => { const error = new Error('请求超时'); error.type = 'TIMEOUT'; reject(error); // 尝试中止请求 if (task && task.abort) { task.abort(); } // 从队列移除 if (config.preventDuplicate) { this.removeFromQueue(requestKey); } }, config.timeout); // 请求完成时清除超时定时器 const originalComplete = task.complete; task.complete = function(...args) { clearTimeout(timeoutTimer); if (originalComplete && typeof originalComplete === 'function') { originalComplete.apply(this, args); } }; } }); // 执行响应拦截器 if (this.responseInterceptor && this.responseInterceptor.onFulfilled) { return requestPromise .then(response => this.responseInterceptor.onFulfilled(response)) .catch(error => { if (this.responseInterceptor.onRejected) { return Promise.reject(this.responseInterceptor.onRejected(error)); } return Promise.reject(error); }); } return requestPromise; } /** * GET请求 * @param {String} url 请求URL * @param {Object} data 请求数据 * @param {Object} options 额外配置 * @returns {Promise} 请求Promise */ get(url, data = {}, options = {}) { return this.request({ ...options, url, data, method: 'GET' }); } /** * POST请求 * @param {String} url 请求URL * @param {Object} data 请求数据 * @param {Object} options 额外配置 * @returns {Promise} 请求Promise */ post(url, data = {}, options = {}) { return this.request({ ...options, url, data, method: 'POST' }); } /** * PUT请求 * @param {String} url 请求URL * @param {Object} data 请求数据 * @param {Object} options 额外配置 * @returns {Promise} 请求Promise */ put(url, data = {}, options = {}) { return this.request({ ...options, url, data, method: 'PUT' }); } /** * DELETE请求 * @param {String} url 请求URL * @param {Object} data 请求数据 * @param {Object} options 额外配置 * @returns {Promise} 请求Promise */ delete(url, data = {}, options = {}) { return this.request({ ...options, url, data, method: 'DELETE' }); } /** * 清除所有请求队列 */ clearQueue() { this.requestQueue.clear(); } } // 导出一个默认实例,方便直接使用 export default new Request(); // 也可以导出类,允许创建多个实例 // export { Request };
// 引入请求库 import request from './request.js'; // 配置全局基础URL request.defaults.baseURL = 'https://api.example.com'; // 添加请求拦截器 request.interceptors.request.use( (config) => { // 在发送请求前做些什么,例如添加token const token = wx.getStorageSync('token'); if (token) { config.header.Authorization = `Bearer ${token}`; } return config; }, (error) => { // 对请求错误做些什么 console.error('请求拦截器错误:', error); return Promise.reject(error); } ); // 添加响应拦截器 request.interceptors.response.use( (response) => { // 对响应数据做点什么 if (response.data.code !== 0) { // 业务错误处理 wx.showToast({ title: response.data.message || '请求失败', icon: 'none' }); return Promise.reject(response.data); } return response.data.data; }, (error) => { // 对响应错误做点什么 if (error.type === 'DUPLICATE_REQUEST') { wx.showToast({ title: error.message, icon: 'none' }); } else if (error.type === 'TIMEOUT') { wx.showToast({ title: '请求超时,请稍后重试', icon: 'none' }); } else { wx.showToast({ title: '网络错误,请稍后重试', icon: 'none' }); } return Promise.reject(error); } ); // 使用示例 - GET请求 request.get('/userinfo', { id: 123 }) .then(data => { console.log('用户信息:', data); }) .catch(error => { console.error('获取用户信息失败:', error); }); // 使用示例 - POST请求 request.post('/login', { username: 'test', password: '123456' }) .then(data => { console.log('登录成功:', data); }) .catch(error => { console.error('登录失败:', error); }); // 临时允许重复请求 request.get('/refresh', {}, { preventDuplicate: false }) .then(data => { console.log('刷新成功:', data); });