微信小程序 --- wx.request网络请求封装

本文围绕小程序网络请求封装展开,介绍了封装 wx.request 的原因,阐述了 request 方法、请求参数设置、快捷方法封装等内容。还提及请求/响应拦截器的定义与完善、并发请求添加、loading 效果处理、uploadFile 封装等,同时说明了小程序环境变量设置和接口调用方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网络请求封装

网络请求模块难度较大,如果学习起来感觉吃力,可以直接学习 [请求封装-使用 npm 包发送请求] 以后的模块

01. 为什么要封装 wx.request

小程序大多数 API 都是异步 API,如 wx.request()wx.login() 等。这类 API 接口通常都接收一个 Object 对象类型的参数,参数中可以按需指定以下字段来接收接口调用结果:

参数名 类型 必填 说明
success function 调用成功的回调函数
fail function 调用失败的回调函数
complete function 调用结束的回调函数(调用成功、失败都会执行)
wx.request({
   
  // 接口调用成功的回调函数
  success() {
   
    wx.request({
   
      success() {
   
        wx.request({
   
          success() {
   
            wx.request({
   
              success() {
   
                wx.request({
   
                  success() {
   
                    wx.request({
   
                      success() {
   
                        wx.request({
   
                          success() {
   
                            wx.request({
   
                              success() {
   }
                            })
                          }
                        })
                      }
                    })
                  }
                })
              }
            })
          }
        })
      }
    })
  },

  // 接口调用失败的回调函数
  fail() {
   },

  // 接口调用结束的回调函数(调用成功、失败都会执行)
  complete() {
   }
})

如果采用这种回调函数的方法接收返回的值,可能会出现多层 success 套用的情况,容易出现回调地狱问题,

为了解决这个问题,小程序基础库从 2.10.2 版本起,异步 API 支持 callback & promise 两种调用方式。

当接口参数 Object 对象中不包含 success/fail/complete 时,将默认返回 promise,否则仍按回调方式执行,无返回值。

但是部分接口如 downloadFile, request, uploadFile 等本身就有返回值,因此不支持 promise 调用方式,它们的 promisify 需要开发者自行封装。

Axios 是我们日常开发中常用的一个基于 promise 的网络请求库

我们可以参考 Axios 的 [使用方式] 来封装自己的网络请求模块,咱们看一下使用的方式:

网络请求模块封装

import WxRequest from 'mina-request'

// 自定义配置新建一个实例
const instance = new WxRequest(({
   
  baseURL: 'https://some-domain.com/api/',
  timeout: 1000,
  headers: {
   'X-Custom-Header': 'foobar'}
})


// 通过 instance.request(config) 方式发起网络请求
instance.requst({
   
  method: 'post',
  url: '/user/12345',
  data: {
   
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
})

// 通过 instance.get 方式发起网络请求
instance.get(url, data, config)

// 通过 instance.delete 方式发起网络请求
instance.delete(url, data, config)

// 通过 instance.post 方式发起网络请求
instance.post(url, data, config)

// 通过 instance.put 方式发起网络请求
instance.put(url, data, config)


// ----------------------------------------------


// 添加请求拦截器
instance.interceptors.request = (config) => {
   

  // 在发送请求之前做些什么
  return config
}

// 添加响应拦截器
instance.interceptors.response = (response) => {
   

  // response.isSuccess = true,代码执行了 wx.request 的 success 回调函数
  // response.isSuccess = false,代码执行了 wx.request 的 fail 回调函数
    
  // response.statusCode // http 响应状态码
    
  // response.config // 网络请求请求参数
    
  // response.data 服务器响应的真正数据
    
  // 对响应数据做点什么
  return response
}

封装后网络请求模块包含以下功能

  1. 包含 request 实例方法发送请求
  2. 包含 get、delete、put、post 等实例方法可以快捷的发送网络请求
  3. 包含 请求拦截器、响应拦截器
  4. 包含 uploadFile 将本地资源上传到服务器 API
  5. 包含 all 并发请求方法
  6. 同时优化了并发请求时 loading 显示效果

02. 请求封装-request 方法

思路分析:

在封装网络请求模块的时候,采用 Class 类来进行封装,采用类的方式封装代码更具可复用性,也方便地添加新的方法和属性,提高代码的扩展性

我们先创建一个 class 类,同时定义 constructor 构造函数

// 创建 WxRequest 类
class WxRequest {
   
  constructor() {
   }
}

我们在 WxRequest 类内部封装一个 request 实例方法

request 实例方法中需要使用 Promise 封装 wx.request,也就是使用 Promise 处理 wx.request 的返回结果

request 实例方法接收一个 options 对象作为形参,options 参数和调用 wx.request 时传递的请求配置项一致

  • 接口调用成功时,通过 resolve 返回响应数据
  • 接口调用失败时,通过 reject 返回错误原因
class WxRequest {
   
  // 定义 constructor 构造函数,用于创建和初始化类的属性和方法
  constructor() {
   }

  /**
   * @description 发起请求的方法
   * @param { Object} options 请求配置选项,同 wx.request 请求配置选项
   * @returns Promise
   */
  request(options) {
   
    // 使用 Promise 封装异步请求
    return new Promise((resolve, reject) => {
   
      // 使用 wx.request 发起请求
      wx.request({
   
        ...options,

        // 接口调用成功的回调函数
        success: (res) => {
   
          resolve(res)
        },

        // 接口调用失败的回调函数
        fail: (err) =>  {
   
          reject(err)
        }
      })
    })
  }
}

然后对 WxRequest 进行实例化,然后测试 request 实例方法是否封装成功!

注意:我们先将类 和 实例化的对象放到同一个文件中,这样方便进行调试,后面我们在拆分成两个文件


class WxRequest {
   
  // coding....
}

// ----------------- 实例化 ----------------------

// 对 WxRequest 进行实例化
const instance = new WxRequest()

// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance

在其他模块中引入封装的文件后,我们期待通过 request() 方式发起请求,以 promise 的方式返回参数

// 导入创建的实例
import instance from '../../utils/wx-request'

Page({
   
    
  // 点击按钮触发 handler 方法
  async handler() {
   
    // 通过实例调用 request 方法发送请求
    const res = await instance.request({
   
      url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
      method: 'GET'
    })

    console.log(res)
  }
})

落地代码:

➡️ /utils/request.js

// 创建 WxRequest 类,采用类的方式进行封装会让方法更具有复用性,也可以方便进行添加新的属性和方法

class WxRequest {
   
  // 定义 constructor 构造函数,用于创建和初始化类的属性和方法
  constructor() {
   }

  /**
   * @description 发起请求的方法
   * @param { Object} options 请求配置选项,同 wx.request 请求配置选项
   * @returns Promise
   */
  request(options) {
   
    // 使用 Promise 封装异步请求
    return new Promise((resolve, reject) => {
   
      // 使用 wx.request 发起请求
      wx.request({
   
        ...options,

        // 接口调用成功的回调函数
        success: (res) => {
   
          resolve(res)
        },

        // 接口调用失败的回调函数
        fail: (err) => {
   
          reject(err)
        }
      })
    })
  }
}

// ----------------- 实例化 ----------------------

// 对 WxRequest 进行实例化
const instance = new WxRequest()

// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance

➡️ /pages/test/test.js

import instance from '../../utils/request'

Page({
   
    
  // 点击按钮触发 handler 方法
  async handler() {
   
    // 第一种调用方式:通过 then 和 catch 接收返回的值
    // instance
    //   .request({
   
    //     url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
    //     method: 'GET'
    //   })
    //   .then((res) => {
   
    //     console.log(res)
    //   })
    //   .catch((err) => {
   
    //     console.log(err)
    //   })

    // 第二种调用方式:通过 await 和 async 接收返回的值
	const res = await instance.request({
   
      url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
      method: 'GET'
    })

    console.log(res)
  }

})

03. 请求封装-设置请求参数

思路分析:

在发起网络请求时,需要配置一些请求参数,

其中有一些参数我们可以设置为默认参数,例如:请求方法、超时时长 等等,因此我们在封装时我们要定义一些默认的参数。

// 默认参数对象
defaults = {
   
  baseURL: '', // 请求基准地址
  url: '', // 开发者服务器接口地址
  data: null, // 请求参数
  method: 'GET',// 默认请求方法
  // 请求头
  header: {
   
    'Content-type': 'application/json' // 设置数据的交互格式
  },
  timeout: 60000 // 小程序默认超时时间是 60000,一分钟
  // 其他参数...
}

但是不同的项目,请求参数的设置是不同的,我们还需要允许在进行实例化的时候,传入参数,对默认的参数进行修改。例如:

// 对 WxRequest 进行实例化
const instance = new WxRequest({
   
  baseURL: 'https://gmall-prod.atguigu.cn/mall-api', // 请求基准地址
  timeout: 10000 // 微信小程序 timeout 默认值为 60000
})

在通过实例,调用 request 实例方法时也会传入相关的请求参数

const res = await instance.request({
   
  url: '/index/findBanner',
  method: 'GET'
})

从而得出结论:请求参数的设置有三种方式:

  1. 默认参数:在 WxRequest 类中添加 defaults 实例属性来设置默认值
  2. 实例化时参数:在对 WxRequest 类进行实例化时传入相关的参数,需要在 constructor 构造函数形参进行接收
  3. 调用实例方法时传入请求参数

默认参数和自定义参数的合并操作,通常会在constructor中进行。

因此我们就在 constructor 中将开发者传入的相关参数和defaults 默认值进行合并,需要传入的配置项覆盖默认配置项

class WxRequest {
   
    
+   // 默认参数对象
+   defaults = {
   
+     baseURL: '', // 请求基准地址
+     url: '', // 开发者服务器接口地址
+     data: null, // 请求参数
+     method: 'GET',// 默认请求方法
+     // 请求头
+     header: {
   
+       'Content-type': 'application/json' // 设置数据的交互格式
+     },
+     timeout: 60000 // 小程序默认超时时间是 60000,一分钟
+   }

  /**
   * @description 定义 constructor 构造函数,用于创建和初始化类的属性和方法
   * @param {*} params 用户传入的请求配置项
   */
+   constructor(params = {
    }) {
   
+     // 在实例化时传入的参数能够被 constructor 进行接收
+     console.log(params)
    
+     // 使用 Object.assign 合并默认参数以及传递的请求参数
+     this.defaults = Object.assign({
   }, this.defaults, params)
+   }
 
  // coding....
}

// ----------------- 实例化 ----------------------

// 对 WxRequest 进行实例化
+ const instance = new WxRequest({
   
+   baseURL: 'https://gmall-prod.atguigu.cn/mall-api',
+   timeout: 15000
+ })

// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance

在调用 request 实例时也会传入相关的参数,是发起请求真正的参数,

我们需要将调用 reqeust 实例方法时传入的参数,继续覆盖合并以后的参数,请求才能够发送成功

注意:让使用传入的参数覆盖默认的参数,同时拼接完整的请求地址。

// 创建 request 请求方法
request(options) {
   
+  // 拼接完整的请求地址
+  options.url = this.defaults.baseURL + options.url
+  // 合并请求参数
+  options = {
    ...this.defaults, ...options }

  return new Promise((resolve, reject) => {
   
    // coding...
  })

}

落地代码:

➡️ utils/request.js

// 创建 Request 类,用于封装 wx.request() 方法
class WxRequest {
   
    
+   // 默认参数对象
+   defaults = {
   
+     baseURL: '', // 请求基准地址
+     url: '', // 开发者服务器接口地址
+     data: null, // 请求参数
+     method: 'GET',// 默认请求方法
+     // 请求头
+     header: {
   
+       'Content-type': 'application/json' // 设置数据的交互格式
+     },
+     timeout: 60000 // 小程序默认超时时间是 60000,一分钟
+   }
    
+   /**
+    * @description 定义 constructor 构造函数,用于创建和初始化类的属性和方法
+    * @param {*} params 用户传入的请求配置项
+    */
+   constructor(params = {
    }) {
   
+     // 在实例化时传入的参数能够被 constructor 进行接收
+     console.log(params)
    
+     // 使用 Object.assign 合并默认参数以及传递的请求参数
+     this.defaults = Object.assign
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端 贾公子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值