axios封装post和get


import axios from 'axios';
import { ElMessage, ElLoading } from 'element-plus';

// 默认配置
const DEFAULT_CONFIG = {
  showError: true, // 默认显示错误提示
  showLoading: false, // 默认不显示loading
  loadingText: '加载中...', // 默认loading文本
  showSuccess: false, // 默认不显示成功提示
  successText: '', // 成功提示文本
  retry: 0, // 默认重试次数
  retryDelay: 1000, // 重试延迟时间
  returnNon200Data: false, // 是否返回非200业务数据
  cancelable: false, // 是否允许取消请求
  timeout:  6000, // 超时时间
};

// 创建axios实例
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: DEFAULT_CONFIG.timeout
});

// 请求队列
let requestQueue = [];
let isRefreshing = false; // 是否正在刷新token
let loadingInstance = null; // loading实例

// 取消请求队列
const pendingCancel = new Map()

// 添加loading
const addLoading = (config) => {
  if (config.showLoading) {
    if (!loadingInstance) {
      loadingInstance = ElLoading.service({
        lock: true,
        text: config.loadingText || DEFAULT_CONFIG.loadingText,
        background: 'rgba(0, 0, 0, 0.7)'
      });
    }
  }
};

// 移除loading
const removeLoading = () => {
  if (loadingInstance) {
    loadingInstance.close();
    loadingInstance = null;
  }
};

// 请求拦截器
service.interceptors.request.use(
  async (config) => {
    // 合并配置参数
    config = { ...DEFAULT_CONFIG, ...config };
    
    // 存储可取消接口map
    if(config.cancelable){
 		const controller = new AbortController();
 		config.signal = controller.signal
        if(pendingCancel.has(config.url)){
            let cancel = pendingCancel.has(config.url)
            cancel()
            pendingCancel.delete(config.url)
        }
		pendingCancel.set(config.url, controller.abort)
	}

    // 添加token
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }

    // 显示loading
    addLoading(config);
    
    return config;
  },
  error => {
    removeLoading();
    return Promise.reject(error);
  }
);


// 响应拦截器
service.interceptors.response.use(
  response => {
    removeLoading();
    
    const { config, data } = response;

    if(config.cancelable && pendingCancel.has(config.url)){
        pendingCancel.delete(config.url)
	}
    
    // 处理成功提示
    if (config.showSuccess) {
      ElMessage.success({
        message: config.successText || data.message || '操作成功',
        duration: 1500
      });
    }

    // 处理业务状态码
    if (data.code !== 200 && !config.returnNon200Data) {
      return Promise.reject(data);
    }

    return config.returnNon200Data ? data : data.data;
  },
  async error => {
    removeLoading();
    
    const { config, response } = error;

    if(config.cancelable && pendingCancel.has(config.url)){
        pendingCancel.delete(config.url)
	}
    
    // 请求取消处理
    if (axios.isCancel(error)) {
      return Promise.reject({ type: 'cancel', message: '请求已取消' });
    }

    // 超时重试逻辑
    if (error.code === 'ECONNABORTED' && config.retry > 0) {
      config.retry--;
      await new Promise(resolve => 
        setTimeout(resolve, config.retryDelay)
      );
      return service(config);
    }

    // 401处理
    if (response?.status === 401) {
      if (!isRefreshing) {
        isRefreshing = true;
        try {
          const newToken = await refreshToken();
          localStorage.setItem('token', newToken);
          error.config.headers.Authorization = `Bearer ${newToken}`;
          // 重试队列中的请求
          requestQueue.forEach(cb => cb(newToken));
          requestQueue = [];
          return service(error.config);
        } catch (e) {
          requestQueue = [];
          localStorage.removeItem('token');
          window.location.href = '/login';
        } finally {
          isRefreshing = false;
        }
      } else {
        return new Promise(resolve => {
          requestQueue.push(() => {
            error.config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`;
            resolve(service(error.config));
          });
        });
      }
    }

    // 错误提示处理
    if (config.showError) {
      const message = response?.data?.message || 
                     error.message ||
                     '请求错误';
      ElMessage.error(message);
    }

    return Promise.reject(error);
  },
);

// Token刷新函数
const refreshToken = async () => {
  const refreshToken = localStorage.getItem('refreshToken');
  const { data } = await axios.post('/auth/refresh', { refreshToken });
  localStorage.setItem('token', data.accessToken);
  return data.accessToken;
};

// 封装请求方法
const createRequest = (method) => {
  return (url, data, config) => {
    const options = {
      method,
      url,
      ...config
    };
    if (method === 'get') {
      options.params = data;
    } else {
      options.data = data;
    }
    return service(options);
  };
};

// 导出常用方法
export const http = {
  get: createRequest('get'),
  post: createRequest('post'),
  put: createRequest('put'),
  delete: createRequest('delete'),
  cancel: (config) => config.cancel?.()
};




http.get('/api/data', { id: 1 }, {
  showLoading: true,
  loadingText: '正在加载数据...'
});


http.post('/api/submit', formData, {
  showSuccess: true,
  successText: '提交成功!'
});

官方文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值