基于wx.request封装类似axios的请求方法

  • 背景
  • 做法


背景

在写H5项目的时候,我们可以通过第三方库axios实现ajax请求,其中使用axios最大的好处便是拦截器,通过拦截器进行请求拦截和响应拦截,之后再依据业务做进一步的处理。而微信小程序中,我们通过wx.request,自己封装,也能实现类似axios的功能。

做法

  1. 配置urlConfig
interface IConfigType {
  backendBaseUrl: string;
  traceUrl: string;
}

// 开发环境地址
const urlDev: IConfigType = {
  backendBaseUrl: 'https://后台地址/dev', // 后台地址
  traceUrl: 'https:/埋点接口地址/dev', // 埋点接口地址
};
// uat环境地址
const urlUat: IConfigType = {
  backendBaseUrl: 'https://后台地址/uat', // 后台地址
  traceUrl: 'https:/埋点接口地址/uat', // 埋点接口地址
};
// 生产环境地址
const urlProd: IConfigType = {
  backendBaseUrl: 'https://后台地址/prod', // 后台地址
  traceUrl: 'https:/埋点接口地址/prod', // 埋点接口地址
};

let env = (wx.getAccountInfoSync()).miniProgram.envVersion || '';

if (wx.getAccountInfoSync) {
  env = (wx.getAccountInfoSync()).miniProgram.envVersion || '';
}

const urlConfig = (): IConfigType => {
  // 通过环境赋值baseURL
  if (env === "release" || !env) { // 正式环境
    return urlProd;
  } else if (env === "trial") { // 体验环境
    return urlUat;
  } else { // 开发环境
    return urlDev;
  }
};

export default urlConfig;
  1. 封装ajax
import urlConfig from './urlConfig';

const baseUrl = urlConfig().backendBaseUrl;
const traceUrl = urlConfig().traceUrl;

let initHeader: any = {
  'content-type': 'application/json',
  'Accept': 'application/json',
};

// 处理登录失效
let handleLoginInvalid = (): void => {
  // 清除登录信息
  wx.removeStorageSync('token');
  wx.removeStorageSync('mobile');
  wx.removeStorageSync('userId');
  wx.removeStorageSync('ownerInvateCode');
  wx.removeStorageSync('openId');
  // 跳转去登录
  // 防止同一页面调用多个接口,导致重复跳转/login
  const pages = getCurrentPages();
  console.log(pages)
  
  if ((pages && pages.length > 1 && ((pages[1].route).indexOf('/login') === -1)) || (pages && pages.length ===1 && ((pages[0].route).indexOf('/login') === -1))) {
    wx.showModal({
      title: '温馨提示',
      content: '请登录',
      showCancel: true,
      success(showModalRes) {
        if (showModalRes.confirm) {
          // console.log('用户点击确定')
          wx.navigateTo({
            url: '/pages/login/login'
          });
        } else if (showModalRes.cancel) {
          // console.log('用户点击取消')
          // wx.reLaunch({
          //   url: '/pages/index/index'
          // })
        }
      }
    })
  } else {
    setTimeout(() => {
      wx.showToast({
        title: '请登录',
        icon: 'error',
        duration: 2000
      })
    }, 500)
  }
}

// 请求拦截
const ajaxInterceptorsRequest = () => {
  // 展示loading
  wx.showLoading({
    title: '加载中',
    mask: true,
  })
  initHeader.token = wx.getStorageSync('token') || '';
}

// 响应拦截
const ajaxInterceptorsResponse = (response: any) => {
  // 隐藏loading
  wx.hideLoading();
  // 隐藏Toast
  // wx.hideToast();
  // 处理错误
  const res = response.data || null;

  if (res && res.code === 0 && response.statusCode === 200) { // 请求成功
    return {
      result: true,
      status: 0
    };
  } else if (res && res.code === 1 && response.statusCode === 200) { // 请求失败
    // 提示错误
    setTimeout(() => {
      wx.showToast({
        title: res.msg,
        icon: 'none',
        duration: 2000
      })
    }, 500)
    return {
      result: false,
      status: 1
    };
  } else if (response.statusCode === 401 || response.statusCode === 403 || response.statusCode === 409) { // 处理token失效的情况,401.token为空或校验失败 403.无权访问其他用户信息 409. 多设备登录被挤下线
    handleLoginInvalid(); // 处理登录失效
    return {
      result: false,
      status: 2
    };
  } else { // 其他错误
    // 提示错误
    setTimeout(() => {
      wx.showToast({
        title: '系统错误,请联系管理员',
        icon: 'none',
        duration: 2000
      })
    }, 500)
    return {
      result: false,
      status: 3
    };
  }
}

class Ajax { // 创建一个类,相当于是创建一个构造函数

  get(url: string, data?: any) { // get方法
    ajaxInterceptorsRequest();

    return new Promise((resolve, reject) => { // 返回一个Promise对象
      wx.request({ // 配合微信的wx.request方法
        url: baseUrl + url, // 默认拼接baseUrl
        data: data || {}, // 如果没有传data,默认为一个空对象
        header: initHeader,
        method: 'GET',
        dataType: 'json',
        responseType: 'text',
        success: (response) => {
          const res: any = response.data;

          const ajaxInterceptorsResponseData = ajaxInterceptorsResponse(response);

          if (ajaxInterceptorsResponseData.result) {
            resolve(res); // 请求成功,执行resolve
          } else if (ajaxInterceptorsResponseData.status === 1) {
            reject(res.msg);
          } else {
            reject(res);
          }
        },

        fail: (res) => { // 请求失败,执行reject
          console.log('请求失败', res)
          reject(res);
        },

        complete: () => { // 请求完成
          wx.hideLoading(); // 隐藏loading
        },
      });
    })
  }

  post(url: string, data?: any) { // post方法
    ajaxInterceptorsRequest();

    return new Promise((resolve, reject) => { // 返回一个Promise对象

      wx.request({ // 配合微信的wx.request方法
        url: baseUrl + url, // 默认拼接baseUrl
        data: data || {}, // 如果没有传data,默认为一个空对象
        header: initHeader,
        method: 'POST',
        dataType: 'json',
        responseType: 'text',
        success: (response) => {
          const res: any = response.data;

          const ajaxInterceptorsResponseData = ajaxInterceptorsResponse(response);

          if (ajaxInterceptorsResponseData.result) {
            resolve(res); // 请求成功,执行resolve
          } else if (ajaxInterceptorsResponseData.status === 1) {
            reject(res.msg);
          } else {
            reject(res);
          }
        },

        fail: (res) => { // 请求失败,执行reject
          console.log('请求失败', res)
          reject(res);
        },

        complete: () => { // 请求完成
          wx.hideLoading(); // 隐藏loading
        },
      })
    })
  }

  trace(data?: any) { // 数据埋点
    let eventId = '';

    // 获取随机数
    const guid = () => {
      let str = '';
      for (; str.length < 19; str += Math.random().toString(36).substr(2)) {
        //
      }
      return str.substr(0, 19);
    }

    eventId = new Date().getTime() + guid();

    const params = {
      type: 'applet',
      tailId: wx.getStorageSync('tailId') || '',
      globalUserId: wx.getStorageSync('userId') || '',
      systemName: 'xgn',
      mobile: wx.getStorageSync('mobile') || '',
      time: new Date().getTime(),
      generateId: wx.getStorageSync('generateId') || '', // 设备标识,md5(openid + systemInfo.brand + systemInfo.model)
      eventId,
      event: data.event || '', // 事件id
      page: data.page || '', // 当前page名
      unionId: wx.getStorageSync('unionId') || '',
      openId: wx.getStorageSync('openId') || '',
      content: data.content || '', // 输入内容
      // fbdId: '', // 不需要
      // systemId: '', // 设备标识
      // applyId: '', // 不需要
      // deviceId: '', // 小程序获取不到
      // browserId: '', // 浏览器指纹,小程序获取不到
      // userAgent: '', // 小程序获取不到
    }

    return new Promise((resolve, reject) => { // 返回一个Promise对象
      wx.request({ // 配合微信的wx.request方法
        url: traceUrl, // 默认拼接traceUrl
        data: [params] || {}, // 如果没有传params,默认为一个空对象
        header: initHeader,
        method: 'POST',
        dataType: 'json',
        responseType: 'text',
        success: (response) => {
          const res = response.data;
          resolve(res)
        },

        fail: (res) => { // 请求失败,执行reject
          console.log('埋点请求失败', res)
          reject(res);
        },

        complete: () => { // 请求完成
        },
      })
    })
  }
}

const ajax = new Ajax() // 创建一个Ajax的实例

export default ajax // 如果想在page中使用Ajax的实例,则写这一句,new Ajax()返回的是一个Ajax实例,是promise对象
  1. 使用封装好的ajax做网络请求
import ajax from "../utils/axiosUtil";

const CommonApi = {
  loginOrRegisterApi: (data: any) => ajax.post(`/userInfo/api/v1/loginOrRegister`, data), // 登录注册一体化
  getloginOrRegisterSmsApi: (data: any) => ajax.post(`/userInfo/api/v1/loginOrRegisterSms`, data), // 登录注册动码获取
  logoutApi: () => ajax.post(`/userInfo/api/v1/logout`), // 注销
};
export default CommonApi;