微信小程序使用Promise封装wx.request

1,941 阅读3分钟

平时开发ReactVue项目时,都是使用axios第三方库来发起http请求处理业务,由于会返回一个Promise对象所以使用起来比较方便。在微信小程序中则提供了一个wx.request的原生api,但使用起来感觉并不好,所以手动封装一层Promise来达到增强使用体验。

封装wx.request

import { removeToken,urlEncode } from "../utils/util";
// removeToken作用只是调用了wx.removeStorageSync删除一些数据
// urlEncode则是将对象解析成a=1&b=2参数格式
// 比较简单,按需实现即可

// 定义api服务地址
const baseUrl = 'http://dev.com:12345';

/**
 * 传入请求参数,返回Promise支持链试调用
 * @param url 请求地址
 * @param method 请求方法类型,不传入默认是"GET"
 * @param data 请求体数据
 * @param params 请求参数
 */
function request(url, method = "GET", data = {}, params = {}) {
  const header = {
    "content-type": "application/json"
    // 有其他content-type需求加点逻辑判断处理即可
  }
  // 获取token,有就丢进请求头
  const tokenString = wx.getStorageSync("access_token");
  if (tokenString) {
    header.Authorization = `Bearer ${tokenString}`;
  }
  return new Promise(function (resolve, reject) {
    // 判断是否传递了query参数,有则进行地址拼接
    // if (params) {
    //   url += "?" + urlEncode(params)
    // }
    wx.request({
      url: baseUrl + url,
      method,
      data,
      dataType: "json", // 微信官方文档中介绍会对数据进行一次JSON.parse
      header,
      success(res) {
        // HTTP状态码为200才视为成功
        if (res.statusCode === 200) {
          // 真正的数据响应体中还有一层success字段判断业务状态,按实际情况处理
          if (res.data.success) {
            resolve(res.data.result)
          } else {
            // 业务判断错误
            reject(res)
          }
        } else if (res.statusCode === 401) {
          // 删除token(401有可能是没穿token,token过期,token不合法等等)并重定向到登录页
          removeToken();
          wx.reLaunch({
            url: "../login/login"
          })
        } else {
          // wx.request的特性,只要有响应就会走success回调,所以在这里判断状态,非200的均视为请求失败
          reject(res)
        }
      },
      fail(err) {
        // 断网、服务器挂了都会fail回调,直接reject即可
        reject(err)
      },
    })
  })
}

// 导出请求和服务地址
export { request, baseUrl}

wx.request和前端常用库axios有所区别,如当请求接口返回状态码为500时,对于axios来说Promise状态会改为rejected,并执行对应的回调。但是对于wx.request来说,只要请求成功了,不管状态码是什么,都会走success的回调,所以不能将请求失败的处理放入fail中,fail只有在如断网等请求没有成功发出处理时才会执行对应回调。

解决办法就是在success回调中进行判断,如HTTP状态码200的视为成功并进入成功逻辑将状态改为fulfilledresolve函数),其他则视为请求失败并将promise状态改为rejectedrejected函数)

接口参数管理

在使用前,可以再通过一个类/函数去统一管理每个模块的接口,在业务逻辑中只需要调用对应的业务接口传参即可,不需要每次都编写冗余url,method,data等等,下面用一个登录业务做例子

import { request } from "../request";

// 管理地址,个人习惯,喜欢的下载request参数中也行
const apiPath = {
  login: "/api/v1/login"
}

class AuthService {
  static login(data){
    // 按住ctrl点击wx.request进入ts声明看options的类型,method是均大写的,对应即可
    return request(apiPath.login, "GET", data)
    
    // 由于request的参数顺序第四个才是查询参数,所以如果需要传递,第三个传输传空对象即可
    // return request(apiPath.login, "GET", {}, data)
  }
}

export default AuthService;

使用封装好的接口服务

import AuthService from "../../service/AuthService";
// 导入封装好的服务层

// 其他代码省略
page({
  // Promise语法
  submitForm(){
    AuthService.login({username:"a",password:"2"}).then(res=>{
      // 干点别的
    },err=>{
      // 出错了干点啥
    })
  },
  // async-await语法糖
  async asycsubmitForm(){
    try{
      const res = await AuthService.login({username:"abc",password:"123"});
      // 干点别的
    }catch(err){
      // 错了干点啥?
    }
  }
})

现在可以愉快的在小程序开发中发起HTTP请求了。 完 :)