1. 为什么我们需要封装 wx.request?
如果你刚开始接触微信小程序开发,大概率会直接用 wx.request 来请求数据。代码写起来大概是这样的:
wx.request({
url: 'https://api.example.com/data',
method: 'GET',
success(res) {
console.log('请求成功', res.data)
},
fail(err) {
console.error('请求失败', err)
},
complete() {
console.log('请求完成')
}
})
看起来挺简单的,对吧?但当你真正开始做一个项目时,问题就来了。想象一下这个场景:你的小程序有几十个页面,每个页面都有好几个接口要调用。每个接口你都要写一遍 wx.request,都要处理一遍 success 和 fail。更头疼的是,很多接口都需要在请求头里带上用户的登录凭证 token,每次请求前你都得从本地存储里读一下 token,然后手动塞到 header 里。万一哪天后端说 token 的字段名要改,或者登录逻辑变了,你就得把所有用到 wx.request 的地方都改一遍,这简直就是一场灾难。
我自己就踩过这个坑。早期项目图快,到处直接写 wx.request,后来要加全局的 loading 效果、要统一处理登录过期、要切换测试和生产环境的域名,差点没改到崩溃。这就是为什么我们需要对网络请求进行封装——把那些重复的、通用的逻辑抽离出来,统一管理。
封装的核心目标有三个:一是让代码更简洁,业务逻辑里只关心请求什么数据和处理什么数据;二是让维护更容易,所有公共逻辑(比如加 token、处理错误)只在一个地方修改;三是提升开发体验和用户体验,比如自动管理 loading 状态、优雅地处理并发请求。
而且,从微信小程序基础库 2.10.2 版本开始,异步 API 开始支持 Promise 风格的调用。这意味着我们可以告别“回调地狱”,用更优雅的 async/await 来写异步代码。我们的封装,就是要基于 Promise,打造一个像 axios 一样好用、甚至更贴合小程序场景的网络请求库。
2. 基础骨架:创建一个 Promise 化的请求类
万事开头难,我们先从搭建一个最基础的骨架开始。我们的思路是创建一个 Class,用面向对象的方式来组织代码,这样后续扩展属性和方法会非常方便。
2.1 创建 WxRequest 类与 request 方法
我们首先创建一个 WxRequest 类。在它的构造函数里,我们先留空,后续会在这里初始化一些默认配置。最关键的是,我们要在类里面创建一个 request 方法,这个方法将是我们所有请求的发起中心。
// utils/request.js
class WxRequest {
constructor() {
// 初始化工作,稍后填充
}
/**
* 发起网络请求
* @param {Object} options 请求配置,和 wx.request 的参数保持一致
* @returns {Promise} 返回一个 Promise 对象
*/
request(options) {
// 核心:用 Promise 包装 wx.request
return new Promise((resolve, reject) => {
wx.request({
...options, // 展开用户传入的所有配置
success: (res) => {
// 请求成功时,通过 resolve 返回结果
resolve(res)
},
fail: (err) => {
// 请求失败时,通过 reject 返回错误
reject(err)
}
})
})
}
}
// 创建类的实例并导出
const instance = new WxRequest()
export default instance
看,代码非常清晰。request 方法接收一个配置对象 options,然后内部用 new Promise 包装了 wx.request。当微信的 success 回调触发时,我们调用 resolve(res) 让外部的 Promise 变为成功状态;当 fail 回调触发时,我们调用 reject(err) 让 Promise 变为失败状态。
2.2 在页面中使用我们封装的请求
现在,我们可以在页面中像使用 axios 一样使用它了。有两种方式,一种是传统的 .then().catch() 链式调用,另一种是更推荐的使用 async/await,让异步代码看起来像同步代码一样直观。
// pages/index/index.js
import request from '../../utils/request'
Page({
async onLoad() {
// 方式一:使用 async/await (推荐)
try {
const res = await request.request({
url: 'https://api.example.com/data',
method: 'GET'
})
console.log('获取到的数据:', res.data)
} catch (err) {
console.error('请求出错:', err)
}
// 方式二:使用 Promise 链
request.request({
url: 'https://api.example.com/data',
method: 'GET'
})
.then(res => console.log(res.data))
.catch(err => console.error(err))
}
})
到这一步,我们已经实现了一个最基础的 Promise 化封装。虽然功能简单,但已经解决了最核心的“回调地狱”问题。不过,这离一个健壮的网络模块还差得远。接下来,我们要给它注入灵魂。
3. 让配置更灵活:默认参数与实例化配置
直接使用上面的封装,你会发现每次请求都要写完整的 URL,还要重复设置 header、timeout 等参数,非常麻烦。我们需要一套灵活的配置系统,允许设置全局默认值,也允许在单个请求中覆盖。
3.1 定义默认配置 (defaults)
我们在 WxRequest 类内部定义一个 defaults 对象,用来存放所有请求的默认配置。
class WxRequest {
// 默认配置
defaults = {
baseURL: '', // 基础路径,如 https://api.example.com
url: '', // 接口路径
data: null, // 请求参数
method: 'GET', // 默认请求方法
header: {
'Content-Type': 'application/j


1416

被折叠的 条评论
为什么被折叠?



