一个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);
  });

 

 
posted @ 2025-08-08 15:03  与f  阅读(16)  评论(0)    收藏  举报