微信小程序 wx.request() 的封装

基于微信小程序的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;
});

功能说明

  1. 加载状态控制

    • 通过showLoading参数控制是否显示加载动画
    • 默认不显示,需要时手动开启
    • 使用微信原生showLoading/hideLoading方法
  2. 拦截器系统

    • 请求拦截器:在请求发送前修改配置
    • 响应拦截器:处理响应数据和错误
    • 支持添加多个拦截器,按添加顺序执行
  3. 并发请求处理

    • all()方法处理多个并发请求

    • 内部使用Promise.all实现

    • 示例用法:

      复制代码
      const [userData, productList] = await http.all([
        http.get('/user'),
        http.get('/products')
      ]);
  4. 重复请求过滤

    • 使用请求方法+URL+参数的哈希值作为唯一标识
    • 相同请求返回缓存中的Promise对象
    • 避免网络资源浪费
  5. 快捷方法

    • 内置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);
  }
}

这个封装方案具有以下优势:

  1. 完整的拦截器系统支持预处理和后处理
  2. 智能的请求缓存机制避免重复请求
  3. 简洁的API设计降低使用复杂度
  4. 完善的错误处理流程
  5. 灵活的加载状态控制
  6. TypeScript友好,可轻松添加类型定义
相关推荐
爱勇宝16 小时前
小红花成长更新了:孩子想要什么,也应该有机会自己说出来
微信小程序·产品·小程序·云开发
andrsted1 天前
企业培训时间难统一?练题簿让在线免费刷题与培训考核更好安排
学习·微信小程序·小程序·学习方法·刷题
拖孩1 天前
一个人 + AI 做的小程序,今天,正式回本了
前端·后端·微信小程序
李纲明1 天前
微信小程序 wx.uploadFile 上传失败:合法域名、临时路径与 HTTPS 证书排查
微信小程序·小程序·uploadfile·devdiy·上传失败
冬奇Lab2 天前
一天一个开源项目(第247篇):wxa-runner —— 让小程序在普通浏览器里用微信官方基础库跑起来,直接接 Playwright 做无头 E2E
微信小程序·开源
andrsted2 天前
练题簿在线免费刷题:让整理过的资料,变成能反复练习的题库
学习·微信小程序·小程序·学习方法·刷题·1024程序员节
梅雅达编程笔记2 天前
Day 17 | uni-app 小程序:前端从零搭建
微信小程序·typescript·uni-app·vue3·pinia·前端开发·全栈
zhiboshequ3 天前
Ai音视频对话在微信小程序端的技术实现方案
人工智能·微信小程序·live-pusher·live-player·音视频对话
小蒜学长3 天前
基于过程性评价的ai助学平台(代码+数据库+LW)
java·spring boot·后端·微信小程序·过程性评价
鸿蒙开发4 天前
# 代码写完才发现不能上线:微信小程序开发前必须准备的 8 件事
微信小程序·产品经理