axios封装进阶——》2

import axios from 'axios';
import { ElLoading, ElMessage } from 'element-plus';
import {getTokenAUTH} from '@/utils/auth';

const pendingMap = new Map();

const LoadingInstance = {
_target: null,
_count: 0
};

function myAxios(axiosConfig, customOptions, loadingOptions) {
const service = axios.create({
baseURL: 'http://localhost:8888', // 设置统一的请求前缀
timeout: 10000, // 设置统一的超时时长
});

// 自定义配置
let custom_options = Object.assign({
repeat_request_cancel: true, // 是否开启取消重复请求, 默认为 true
loading: false, // 是否开启loading层效果, 默认为false
reduct_data_format: true, // 是否开启简洁的数据结构响应, 默认为true
error_message_show: true, // 是否开启接口错误信息展示,默认为true
code_message_show: false, // 是否开启code不为0时的信息提示, 默认为false
}, customOptions);

// 请求拦截
service.interceptors.request.use(
config => {
removePending(config);
custom_options.repeat_request_cancel && addPending(config);
// 创建loading实例
if (custom_options.loading) {
LoadingInstance._count++;
if(LoadingInstance._count === 1) {
LoadingInstance._target = ElLoading.service(loadingOptions);
}
}
// 自动携带token
if (getTokenAUTH() && typeof window !== "undefined") {
config.headers.Authorization = getTokenAUTH();
}

  return config;
}, 
error => {
  return Promise.reject(error);
}

);

// 响应拦截
service.interceptors.response.use(
response => {
removePending(response.config);
custom_options.loading && closeLoading(custom_options); // 关闭loading

  if(custom_options.code_message_show && response.data && response.data.code !== 0) {
    ElMessage({
      type: 'error',
      message: response.data.message
    })
    return Promise.reject(response.data); // code不等于0, 页面具体逻辑就不执行了
  }

  return custom_options.reduct_data_format ? response.data : response;
},
error => {
  error.config && removePending(error.config);
  custom_options.loading && closeLoading(custom_options); // 关闭loading
  custom_options.error_message_show && httpErrorStatusHandle(error); // 处理错误状态码
  return Promise.reject(error); // 错误继续返回给到具体页面
}

);

return service(axiosConfig)
}

export default myAxios;

/**

  • 处理异常
  • @param {*} error
    */
    function httpErrorStatusHandle(error) {
    // 处理被取消的请求
    if(axios.isCancel(error)) return console.error('请求的重复请求:' + error.message);
    let message = '';
    if (error && error.response) {
    switch(error.response.status) {
    case 302: message = '接口重定向了!';break;
    case 400: message = '参数不正确!';break;
    case 401: message = '您未登录,或者登录已经超时,请先登录!';break;
    case 403: message = '您没有权限操作!'; break;
    case 404: message = 请求地址出错: ${error.response.config.url}; break; // 在正确域名下
    case 408: message = '请求超时!'; break;
    case 409: message = '系统已存在相同数据!'; break;
    case 500: message = '服务器内部错误!'; break;
    case 501: message = '服务未实现!'; break;
    case 502: message = '网关错误!'; break;
    case 503: message = '服务不可用!'; break;
    case 504: message = '服务暂时无法访问,请稍后再试!'; break;
    case 505: message = 'HTTP版本不受支持!'; break;
    default: message = '异常问题,请联系管理员!'; break
    }
    }
    if (error.message.includes('timeout')) message = '网络请求超时!';
    if (error.message.includes('Network')) message = window.navigator.onLine ? '服务端异常!' : '您断网了!';

ElMessage({
type: 'error',
message
})
}

/**

  • 关闭Loading层实例
  • @param {*} _options
    */
    function closeLoading(_options) {
    if(_options.loading && LoadingInstance._count > 0) LoadingInstance._count--;
    if(LoadingInstance._count === 0) {
    LoadingInstance._target.close();
    LoadingInstance._target = null;
    }
    }

/**

  • 储存每个请求的唯一cancel回调, 以此为标识
  • @param {*} config
    */
    function addPending(config) {
    const pendingKey = getPendingKey(config);
    config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
    if (!pendingMap.has(pendingKey)) {
    pendingMap.set(pendingKey, cancel);
    }
    });
    }

/**

  • 删除重复的请求
  • @param {*} config
    */
    function removePending(config) {
    const pendingKey = getPendingKey(config);
    if (pendingMap.has(pendingKey)) {
    const cancelToken = pendingMap.get(pendingKey);
    // cancelToken()这里传递的pendingKey可以给到上面异常处理传递一个提示信息,查看控制台能打印取消的接口情况。
    // if(axios.isCancel(error)) return console.error('请求的重复请求:' + error.message);
    cancelToken(pendingKey);
    pendingMap.delete(pendingKey);
    }
    }

/**

  • 生成唯一的每个请求的唯一key
  • @param {*} config
  • @returns
    */
    function getPendingKey(config) {
    let {url, method, params, data} = config;
    if(typeof data === 'string') data = JSON.parse(data); // response里面返回的config.data是个字符串对象
    return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&');
    }
    image
    image
    image
    image
    image
posted @   举个栗子走天下  阅读(162)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示