axios使用记录

98 阅读3分钟

拦截器配置

使用场景:

  1. 路由拦截

导航守卫 + requiresAuth + 响应拦截器

router.beforeEach((to, from) => {
  if (to.meta.requiresAuth && !token) {
    // 此路由需要授权,请检查是否已登录
    // 如果没有,则重定向到登录页面
    return {
      path: '/login',
      // 保存我们所在的位置,以便以后再来
      query: { redirect: to.fullPath },
    }
  }
});

// 使用响应拦截器处理本地token失效情况,强制用户重新登录
axios.interceptors.response.use(
  () => {},
  (error) => {
    if (error.response.status) {
      switch (error.response.status) {
        // token失效
        case 401:
          // 清空token, 跳转登录页
          break;
          
          ....
          ....
      }
    }
})
  1. 统一处理http请求与响应
  • 登录失效处理
  • 请求头添加token
  • 对响应错误分类处理
  • showLoading加载动画处理
  • 对响应数据的嵌套层级过深的处理
// 定义拦截器,实现拦截功能单一化
import request from './request/index'; // 定义请求拦截器
import response from './response/index';  // 定义响应拦截器

// 定义拦截器调度器,注册所有拦截器
export const setInterceptors = instance => {
   
   if(!instance) return;

    // 设置请求拦截器
    for (const key in request) {
        instance.interceptors.request.use((config) => request[key](config));
    }

    // 设置响应拦截器
    for (const key in response) {
        instance.interceptors.response.use((response) => response[key](response));
    }
    return instance;
}

// 响应错误分类处理
axios.interceptors.response.use(
  (response) => {},
  (error) => {
    if (error.response.status) {
      switch (error.response.status) {
        // token失效
        case 401:
          // 清空token, 跳转登录页
          break;
        // 404请求不存在
        case 404:
          ...
          break;
        // SQL语句错误
        case 500:
          ...
          break;
          
        // 针对其他错误的处理
        ....
        ....
      }
    }
    return Promise.reject(error.response);
  },
);
  1. 请求取消, 解决并发冲突

使用api: CancelToken, AbortController(v0.22.0+); 并发冲突:不同用户在较短时间间隔内进行相同的操作,或者某一个用户进行的重复提交操作

请求取消:

let cancel;
axios.get('/user/12345', {
    cancelToken: new axios.CancelToken(function executor(c) { 
        // executor 函数接收一个 cancel 函数作为参数
        cancel = c;
    })
});
// 取消请求
cancel();


// AbortController实现
// const controller = new AbortController();
let source = axios.CancelToken.source();
axios.get('/user/12345', {
    cancelToken: source.token,
    // signal: controller.signal
}).catch(function (thrown) {
    if (axios.isCancel(thrown)) {
        console.log('Request canceled', thrown.message);
    } else {
     // 处理错误
    }
});
source.cancel('取消请求');
// 恢复请求
source = axios.CancelToken.source();
// controller.abort();

并发解决:

  1. 一般通用的解决方案

给页面控件添加Loading效果,避免用户重复点击操作

  1. 使用拦截器 + 路由导航守卫解决并发冲突:
// 1. 缓存所有进行中的请求(使用url + 方法名作为请求的标识),并在此次请求发送前进行判断,有则取消
// 2. 请求完成在缓存的请求列表中清除该请求
// 3. 如有需要,响应拦截器中设置相同的请求再次触发时需要满足的延迟条件(避免短时间内大量重复发送)
// 4. 某些特定情况下(网络问题、超时、路由切换)清空缓存的请求
this.pendings = new Map();

axios.interceptors.request.use(
  (config) => {
    // 缓存请求,并对当前请求进行判断
    this.pendings.set(url, cancel);
  },
  (error) => {
    // 网络波动或者超时等情况,清空 pendingRequests 对象
    pendingRequests.clear();
    return Promise.reject(error);
  }
);

axios.interceptors.response.use(
  (response) => {
    // 从缓存列表中清除该请求
    // 如有必要,设置再次触发请求的延迟
    setTimeout(() => {
      this.pendings.remove();
    }, 1000);
  },
  (error) => { 
    if (axios.isCancel(error)) {
      return Promise.reject(error);
    }
    pendingRequests.clear();
    return Promise.reject(error);
  }
)

router.beforeEach((to, from, next) => {
  // 路由跳转要清除之前所有的请求缓存
  this.pendings.clear();
  next();
})

请求参数配置

params序列化

get请求参数类型为数组时,queryString被编码为如下格式

{
    types: [1,2],
    keyword: 'aaa bbb'
}
types[]=1&types[]=2&keyword=aaa+bbb    // 后端无法解析types

解决方法:
1. 使用URLSearchParams对象
const params = new URLSearchParams();
params.append('types', [1,2]);
params.append('keyword', 'aaa bbb');
// 编码为
types=1%2C3&keyword=aaa+bbb

2. 使用paramsSerializer配置选项
(1) qs库
paramsSerializer: (params) => Qs.stringify(params, { indices: false })
// types=1&types=2&keyword=aaa%20bbb
(2) encodeURI/Array.join()
针对值为数组的参数,使用encodeURI/Array.join()
// types=1,2&keyword=aaa+bbb

补充: qs与queryString的区别:querystring无法解析嵌套对象


后语

实际项目中axios的一些封装使用:

拦截器调度器配置(单一化拦截器功能)、全局错误处理、特殊场景处理(如取消重复请求、请求异常处理、路由拦截等)

未完待续~~~~~~

参考链接: 77.9K Star 的 Axios 项目有哪些值得借鉴的地方优雅管理axios拦截器qsjs-URI编码、解码