为什么需要封装
小程序里发请求,直接写 wx.request 当然能用,但项目一大就难受了:每个页面都要拼一遍域名、拼一遍 token、处理一遍错误码,代码全是重复的。把请求统一封装成一层,是所有中大型小程序的必经之路。
封装之后,页面代码只管业务:调一个 request 方法,传路径和参数,拿回数据或者统一报错。域名、鉴权、超时、重试这些杂事,全收在请求层里。
好的请求层一般提供几个能力:统一的请求头、自动带 token、拦截响应做登录态过期处理、网络错误自动重试。下面一步一步来。
- 封装request 统一出口。
- 拦截请求与响应拦截。
- 鉴权token 自动携带与续期。
- 容错超时、重试与并发。
基础请求封装
先做一个 request 方法,把域名、公共参数、错误处理都定好。返回 Promise,页面用起来是异步的,不用再嵌套回调。
function request(options) {
var base = 'https://api.example.com';
return new Promise(function (resolve, reject) {
wx.request({
url: base + options.url,
method: options.method || 'GET',
data: options.data || {},
header: options.header || {},
success: function (res) { resolve(res.data); },
fail: function (err) { reject(err); }
});
});
}
页面里这样用:request 一个路径,then 里拿数据,catch 里统一弹错误。公共的逻辑全在封装里,页面代码不再关心域名和底层细节。
封装还可以顺手把参数序列化、请求日志、环境切换做进去。比如本地联调指向测试环境,上线自动切生产,全在请求层一处配置,不用每个页面去改地址。
拦截器与统一鉴权
请求发出前,要自动带上登录态;响应回来后,先看看业务码正不正常。这两段逻辑放在封装里,就叫请求拦截和响应拦截。
function request(options) {
var token = wx.getStorageSync('token');
if (token) options.header.Authorization = token;
return new Promise(function (resolve, reject) {
wx.request({
url: base + options.url,
header: options.header,
success: function (res) {
if (res.data.code === 401) {
wx.navigateTo({ url: '/pages/login/login' });
reject(res.data);
} else {
resolve(res.data);
}
}
});
});
}
业务码统一约定:0 表示成功,401 表示登录过期,5xx 表示服务端异常。判断统一放在一处,页面上就不用每个请求都写一遍 if code。
登录过期还有一种处理:先拿 refresh token 静默续期,续上就重放原请求,用户完全无感;续不上再跳登录页。这样能把被动跳登录的情况降到最少。
超时与重试
弱网环境下,请求超时和失败是家常便饭。wx.request 自带 timeout 配置,超时进入 fail 分支。对于 GET 这类幂等请求,可以自动重试一两次,POST 就要小心,重试可能造成重复下单。
| 场景 | 策略 | 说明 |
|---|---|---|
| GET 查询 | 自动重试 1-2 次 | 幂等,安全 |
| POST 下单 | 不自动重试 | 防重复,提示用户 |
| 上传文件 | 分片断点重传 | 只重传失败分片 |
重试要有间隔,别死循环。重试次数多了还是失败,就给用户一个友好提示加手动重试按钮。
重试的间隔可以递增,第一次等两秒,第二次等四秒,给网络一个恢复的时间窗口。同时记录一下失败率,某个接口失败率突然飙升,多半是服务端出问题了,尽早告警而不是默默重试。
弱网模式的判断也可以做进请求层:网络类型切到 2G 或者无网时,提前拦截一部分不紧急的请求,等网络恢复再发,避免请求一窝蜂堵在门口。
调试体验也可以顺手提升:请求层统一打日志,记录请求路径、耗时、状态码,开发期在控制台一眼看清哪个接口慢、哪个报错。线上把日志关掉,只保留错误上报,别把日志打到生产环境刷屏。
最后,封装不是越复杂越好。团队小、接口少的时候,一个 request 方法加 token 就够;等页面多了再逐步加拦截器、重试和缓存。先跑起来,再根据真实痛点加能力,比一上来就堆一套重型框架更实在。
并发与缓存
页面一次可能要并发拉好几个接口,封装层可以做并发控制,比如同时最多发五个,避免把带宽打满。数据不常变的接口,加上缓存,二次进入秒开。
请求层做得好,弱网体验和首屏速度都会跟着变好。
缓存要带过期时间,写清楚 key 的命名规则,别把用户敏感数据塞进缓存。登录态失效时,顺手把相关缓存一起清掉。
常见网络坑
| 坑 | 后果 | 应对 |
|---|---|---|
| 域名没配白名单 | 请求被拦 | 后台配置合法域名 |
| token 过期不处理 | 接口全挂 | 401 统一跳登录 |
| POST 盲目重试 | 重复下单 | 写操作不自动重试 |
| 并发无限制 | 带宽打满 | 加并发控制 |
落地清单
- 请求统一走封装出口。
- token 自动带、401 统一处理。
- GET 可重试,POST 不重试。
- 加并发控制和带过期时间的缓存。
- 失败提示友好,保留手动重试。
请求层是地基,地基稳了,业务盖多高都不怕。