微信小程序-网络相关的二次封装

目录

一、特点

二、使用教程

1.新建HttpUtil.js文件 

2.构建拦截器

3.调用方式

4.结语


一、特点

  1. 可以类似axios一样对网络请求的统一拦截
  2. 统一使用Promise方式返回
  3. 文件上传和网络请求使用统一拦截器处理
  4. 支持请求的取消

二、使用教程

1.新建HttpUtil.js文件 

代码如下所示:

//构建短的uuid 
function generateShortUUID() {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  let shortUUID = '';
  for (let i = 0; i < 8; i++) {
    const randomIndex = Math.floor(Math.random() * chars.length);
    shortUUID += chars.charAt(randomIndex);
  }
  return shortUUID;
}
//二次封装网络请求
export default class HttpUtil {
  //请求的默认配置
  #config = {
    baseUrl: "",
    timeout: 60000
  };
  //请求任务队列,结构如下:{type:{uuid:task}}
  #requestTask = {};
  //拦截器
  #interceptors = {
    preRequest: undefined,
    preReponse: undefined,
    errorReponse: undefined
  }; //拦截器,支持单个拦截够用了
  constructor(config) {
    if (config) {
      this.#config = config;
    }
    this.#requestTask = {};
  }
  get(url, data) {
    return this.request({
      url,
      data,
      method: "GET",
    });
  }
  post(url, data) {
    return this.request({
      url,
      data,
      method: "POST",
    });
  }
  put(url, data) {
    return this.request({
      url,
      data,
      method: "PUT",
    });
  }
  delete(url, data) {
    return this.request({
      url,
      data,
      method: "DELETE",
    });
  }
  /**
   * 拦截器-发送请求前
   * @param {*} preRequest 返回修改后的config
   */
  useRequestInterceptor(preRequest) {
    this.#interceptors.preRequest = preRequest;
  }
  /**
   * 拦截器-得到响应结果前
   * @param {Promise} onSuccess  必须返回一个Promise对象
   * @param {Promise} onError  必须返回一个Promise对象
   */
  useReponseInterceptor(onSuccess, onError) {
    this.#interceptors.preReponse = onSuccess;
    this.#interceptors.errorReponse = onError;
  }

  /**
   * 发送请求
   * @param {*} config wx.request参数配置
   * @param {String} type 可以用于取消请求,细看:当前类的abort方法
   */
  request(config, type) {
    return this.#httpTask(config, false, type);
  }
  /**
   * 文件上传
   * @param {String} url 地址
   * @param {String} name 文件对应的字段名
   * @param {String} filePath 文件地址
   * @param {*} otherConfig 其他配置
   * @param {Function} onProgressUpdate 进度监听
   * @param {String} type 可以用于取消请求,细看:当前类的abort方法
   * 
   */
  uploadFile(url, name, filePath, otherConfig, onProgressUpdate, type) {
    const config = {
      ...otherConfig,
      url,
      name,
      filePath,
      onProgressUpdate,
    };
    return this.#httpTask(config, true, type);
  }
  /**
   * 取消请求,按照type作为大类,相同type的都统一被取消掉
   * 使用场景:页面切换,当前页面发起的,但是没有完成的请求都没用了,就可以取消掉
   * 例如:我们定义了图片上传页面的type值为:uploadImg,但是页面离开了,你就可以在生命周期的onUnload函数中调用httpUtil.abort("uploadImg"),将还没有上传的完成的图片取消掉
   * @param {*} type 分类值
   */
  abort(type = "default") {
    const tasks = this.#requestTask[type];
    if (tasks) {
      for (const uuid in tasks) {
        const task = tasks[uuid];
        task.abort();
      }
      delete this.#requestTask[type];
    }
  }
  /**
   * 添加请求任务
   * @param {String} type 分类
   * @param {String} uuid 唯一标识
   * @param {*} requestTask 请求任务
   */
  #requestTaskAdd(type, uuid, requestTask) {
    if (!this.#requestTask[type]) {
      this.#requestTask[type] = {};
    }
    this.#requestTask[type][uuid] = requestTask;
  }
  /**
   * 移除请求任务
   * @param {String} type 分类
   * @param {String} uuid 唯一标识
   */
  #requestTaskremove(type, uuid) {
    if (this.#requestTask[type] && this.#requestTask[type][uuid]) {
      delete this.#requestTask[type][uuid];
    }
  }
  /**
   * 统一发送请求处理
   * @param {*} config 配置参考wx.request
   * @param {*} isFile 是否是文件上传
   * @param {*} type 分类
   */
  #httpTask(config, isFile = false, type = "default") {
    return new Promise((resolve, reject) => {
      const uuid = generateShortUUID();
      config.timeout = config.timeout || this.#config.timeout;
      //相对路径补上baseUrl
      if (/^(\/|\.\.?\/)/.test(config.url)) {
        config.url = this.#config.baseUrl + config.url;
      }
      if (this.#interceptors.preRequest) {
        config = this.#interceptors.preRequest(config);
      }
      //请求成功
      config.success = (res) => {
        this.#requestTaskremove(type, uuid);
        // 是否有拦截器
        if (this.#interceptors.preReponse) {
          this.#interceptors.preReponse(res).then(resolve).catch(reject);
        } else {
          resolve(res);
        }
      };
      //请求失败
      config.fail = (err) => {
        this.#requestTaskremove(type, uuid);
        // 是否有拦截器
        if (this.#interceptors.errorReponse) {
          this.#interceptors.errorReponse(err).then(resolve).catch(reject);
        } else {
          reject(err);
        }
      };
      let task = null;
      if (isFile) {
        const onProgressUpdate = config.onProgressUpdate;
        delete config.onProgressUpdate;
        //start------处理一下文件上传返回的结果是字符串,不是json对象
        const success = config.success;
        config.success = (res) => {
          res.data = JSON.parse(res.data)
          success(res);
        }
        //end-------处理一下文件上传返回的结果是字符串,不是json对象
        task = wx.uploadFile(config);
        //如果设置了监听
        if (onProgressUpdate) {
          task.onProgressUpdate(onProgressUpdate)
        }
      } else {
        task = wx.request(config);
      }
      this.#requestTaskAdd(type, uuid, task);
    })
  }

}
2.构建拦截器
const request = new HttpUtil({
  baseUrl: "xxxxx"
})

/**
 * 请求发送前拦截器
 */
request.useRequestInterceptor(config => {
  const token = getToken();//TODO 获取token
  if (token) {
    config.header = {
      ...config.header,
      token: token
    }
  }
  return config;
});

/**
 * 得到响应结果前的拦截器
 */
request.useReponseInterceptor( res => {
  const data = res.data;
  //接口调用成功
  if (res.statusCode === 200 && data.code === 200) {
    return Promise.resolve(res.data.data);
  }
  const msg = data.msg || data.error || data.message || res.errMsg;
  //TODO 授权失败
  if (res.statusCode === 401 || data.code === 401) {
       //没权限处理
  }else {
    //TODO 提示等处理
  }
  return Promise.reject(new Error(msg));
},  error => {
  // 接口调用失败
  if (error.errMsg.indexOf("request:fail abort") !== -1) {
    return Promise.reject(new Error(error.errMsg));
  }
  wx.showToast({
    title: error.errMsg,
    icon: "error",
    duration: 1500
  });
  return Promise.reject(new Error(error.errMsg));
})
export default request;

3.调用方式
// 登录
request.post('/v1/login', data).then(data=>{});
// 获取用户信息
request.get('/v1/userInfo', params).then(data=>{});
// 修改用户信息
request.put('/v1/userInfo', data).then(data=>{});
// 删除用户
request.delete('/v1/userInfo', data).then(data=>{});
// 复杂请求,请参考wx.request参数
request.request({
    url:"xxxxx",
    header:{
        a:1
    },
    data:{
        b:2    
    },
    method:"POST"
}).then(data=>{});
//统一文件上传接口
request.uploadFile("/v1/file/upload", "file", filePath).then(data=>{});
//取消请求----具体细看HttpUtil.js类中的abort函数
request.abort()
4.结语

        代码上如果有bug欢迎私信或者评论,我尽自己所能解答和修改

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值