抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

这次花了很大精力,完整的写了一套通用的请求库,带拦截器功能

Why do this ?

简单点,用Promise把请求成功后的data给resolve了,失败后的error给reject了就行了。

但因为这次需要loading,判断token,而且所有接口都需要在header中添加token请求,简单的包一层Promise未免有些力不从心了。

这次封装的是微信小程序自带的请求方法,其实可以推广到所有异步请求的类库。

intercor achieve

具体讲讲interceptor的实现

initialization

类中存一个interceptor对象,这个对象自带两个Queue,请求前执行的函数和请求结束执行的函数。

因为请求之后会有成功和失败,所以这个Queue有successFunc、failFunc

对外开放添加拦截器的方法

process

在请求开始之前,调用request时传来的config不会立即带入,先扔进请求拦截器,对config做一些处理之后,再将config落实到请求方法上。

在请求结束后,将返回的数据不会立即返回,而是先扔进响应拦截器,正常执行的话,走successFunc,另一种情况请求失败reject时被catch住,在catch里执行failFunc。

在请求结束后的两种分支下返回本次请求的结果

下面给出具体代码

// 存放BaseURL的配置文件
const devConfig = require("./config");

// 网络请求文件request.js
class Axios {
  constructor(config) {
    this.config = Object.assign(
      {
        timeout: 3_000,
        dataType: "json",
      },
      config
    );

    //拦截器对象
    this.interceptor = {
      reqQueue: [],
      resQueue: [],
      request(configFunc) {
        this.reqQueue.push(configFunc);
      },

      response(successFunc, failFunc) {
        this.resQueue.push({
          successFunc,
          failFunc,
        });
      },
    };

    //添加GET,POST.PUT.DELETE四种方法
    ["post", "get", "put", "delete"].reduce((pre, method) => {
      pre[method] = function (url, data, shouldLoding) {
        return this.request.call(
          this,
          Object.assign(this.config || {}, {
            url,
            method,
            data: data || {},
            shouldLoding: shouldLoding === undefined ? true : false,
          })
        );
      };
      return pre;
    }, this);
  }

  async request(conf) {
    //执行request拦截器
    const config = this.interceptor.reqQueue.reduce(
      (prev, cur) => cur.call(this, prev),
      conf
    );
      
    try {
      let res = await new Promise((resolve, reject) => {
        wx.request({
          method: config.method,
          url: devConfig.host + config.url,
          data: config.data || {},
          header: config.header || {
            "content-type": "application/json",
          },
          success(res) {
            resolve(res);
          },
          fail(err) {
            reject(err);
          },
        });
      });
      //成功响应拦截器
      try {
        for (const interceptor of this.interceptor.resQueue) {
          res = await interceptor.successFunc.call(this, res);
        }
        return res;
      } catch (InterceptorError) {
        return Promise.reject(InterceptorError);
      } //ok response
    } catch (HTTPError) {
      // 失败响应拦截器
      try {
        let error = HTTPError;
        for (const interceptor of this.interceptor.resQueue) {
          error = await interceptor.failFunc.call(this, error);
        }
        return error;
      } catch (InterceptorError) {
        return Promise.reject(InterceptorError);
      } // fail response
    }
  }
}

module.exports = axios;

在文件中添加几个拦截器测试


let axios = new Axios();
//请求拦截器
axios.interceptor.request((config) => {
  // 请求前loding
  if (config.shouldLoding) {
    wx.showLoading({
      title: "正在加载中...",
      icon: "loading",
    });
  }

   // 判断本地是否存在token
  let token = wx.getStorageSync("token");
  if (!token) {
    wx.showToast({
      title: "未登录,请先登录!",
      icon: "loading",
    });
    setTimeout(() => {
      wx.switchTab({
        url: "/pages/user/index",
      });
    }, 2_000);
  }
    
  config["header"] = {
    Authorization: token,
    "Content-Type": "application/x-www-form-urlencoded",
  };
  return config || {};
});

//响应拦截器
const UNLOGIN = 401;
axios.interceptor.response(
  (res) => {
    
   	// 结束loding
    wx.hideLoading();
    // 未登录, reject结束业务流程
    if (res.statusCode === UNLOGIN) {
      return Promise.reject({
        msg: "未登录,跳转登录界面",
      });
    }
    return Promise.resolve(res.data);
  },
  (err) => {
    wx.hideLoading();
    console.log("失败响应拦截");
    return Promise.reject(err);
  }
);

axios.interceptor.response(
  (res) => {
    console.log("成功响应拦截2");
    return Promise.resolve(res);
  },
  (err) => {
    wx.hideLoading();
    console.log("失败响应拦截2");
    return Promise.reject(err);
  }
);
axios.interceptor.response(
  (res) => {
    console.log("成功响应拦截3");
    return Promise.resolve(res);
  },
  (err) => {
    wx.hideLoading();
    console.log("失败响应拦截3");
    return Promise.reject(err);
  }
);

效果:

image-20210913204709012

image-20210913204750820

经过今晚一阵梳理之后,现在看来一切都是那么的合理,哈哈哈哈。

wx:request也可以换成别的请求库哦!

评论