Axios封装——可以撤回

74 阅读2分钟

安装依赖

nprogress 是一个用于显示加载进度条的库,可以帮助实现 loading 效果。

npm install axios nprogress

封装 axios

src/utils/request.js

import axios from 'axios';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';

// 设置取消请求的 token
const CancelToken = axios.CancelToken;
let pendingRequests = new Map(); // 用于存储请求队列

// 添加请求到队列
const addRequestToQueue = (config) => {
  const requestKey = `${config.method}:${config.url}`;
  config.cancelToken = new CancelToken((cancel) => {
    if (!pendingRequests.has(requestKey)) {
      pendingRequests.set(requestKey, cancel);
    }
  });
};

// 移除队列中的请求
const removeRequestFromQueue = (config) => {
  const requestKey = `${config.method}:${config.url}`;
  if (pendingRequests.has(requestKey)) {
    const cancel = pendingRequests.get(requestKey);
    cancel(requestKey);
    pendingRequests.delete(requestKey);
  }
};

// 清空请求队列(用于页面切换时取消请求)
export const clearRequestQueue = () => {
  pendingRequests.forEach((cancel, key) => {
    cancel(key);
  });
  pendingRequests.clear();
};

// 根据环境变量设置基础URL
const baseURL = process.env.NODE_ENV === 'production' ? 'https://api.production.com' : 'https://api.development.com';

// 创建 axios 实例
const service = axios.create({
  baseURL: baseURL,
  timeout: 5000, // 超时时间
  headers: {
    'Content-Type': 'application/json',
  }
});

// 请求拦截器
service.interceptors.request.use(
  (config) => {
    // 启动进度条
    NProgress.start();

    // 自动添加 Token 到请求头
    const token = localStorage.getItem('token');
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`;
    }

    // 添加请求到队列,防止重复请求
    removeRequestFromQueue(config);
    addRequestToQueue(config);

    return config;
  },
  (error) => {
    // 关闭进度条
    NProgress.done();
    return Promise.reject(error);
  }
);

// 响应拦截器
service.interceptors.response.use(
  (response) => {
    // 关闭进度条
    NProgress.done();

    // 请求成功后移除队列中的该请求
    removeRequestFromQueue(response.config);

    const res = response.data;
    
    // 自定义状态码处理
    if (res.code !== 200) {
      // 错误处理
      console.error('Error:', res.message);
      
      // 比如处理 token 过期
      if (res.code === 401) {
        console.error('Token expired, redirecting to login...');
        // 可以执行登出操作,或跳转到登录页面
      }
      return Promise.reject(new Error(res.message || 'Error'));
    } else {
      return res; // 返回处理过的数据
    }
  },
  (error) => {
    // 关闭进度条
    NProgress.done();

    // 请求失败时清除队列中的该请求
    removeRequestFromQueue(error.config || {});

    return Promise.reject(error);
  }
);

export default service;

使用导航守卫取消未完成请求

在页面切换时,通过 Vue Router 的导航守卫取消未完成的请求。 src/router/index.js

import Vue from 'vue';
import Router from 'vue-router';
import { clearRequestQueue } from '@/utils/request'; // 引入清除请求队列的函数

Vue.use(Router);

const router = new Router({
  routes: [
    // 定义你的路由
  ]
});

router.beforeEach((to, from, next) => {
  // 页面切换前取消所有未完成的请求
  clearRequestQueue();
  next();
});

export default router;

在组件中使用 axios 封装

在 Vue 组件中使用封装的 axios

<template>
  <div>
    <h1>{{ data }}</h1>

  </div>

</template>

<script>
import service from '@/utils/request';

export default {
  data() {
    return {
      data: null,
    };
  },
  async created() {
    try {
      const response = await service.get('/some-endpoint');
      this.data = response.data;
    } catch (error) {
      console.error('Error fetching data:', error);
    }
  }
};
</script>