为什么需要封装

小程序里发请求,直接写 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 的命名规则,别把用户敏感数据塞进缓存。登录态失效时,顺手把相关缓存一起清掉。