用axios和fetch分别封装请求

1.axios的封装请求

javascript 复制代码
import axios from "axios";
import { apiUrl } from "@/config/global-config.js";
import { useUserStore } from "../stores";
import { usePageRoute } from "@/composable/usePageRoute.js";

// 创建 axios 实例
const instance = axios.create({
  baseURL: apiUrl,
  timeout: 60000,
  headers: { "Content-Type": "application/json" },
});

// 刷新token的方法
const refreshToken = async () => {
  const userStore = useUserStore();
  try {
    const response = await instance.post(
      "/auth/refresh",
      {},
      {
        headers: { Authorization: `Bearer ${userStore.token}` },
      }
    );

    if (response.data.code === 200) {
      userStore.setToken(response.data.data.token);
      return true;
    }
    return false;
  } catch (error) {
    return false;
  }
};

let isRefreshing = false; // 是否正在刷新token
let refreshSubscribers = []; // 存储等待的请求

// 通知所有等待的请求
const onRefreshed = (token) => {
  refreshSubscribers.forEach((callback) => callback(token));
  refreshSubscribers = [];
};

// 添加请求到等待队列
const addSubscriber = (callback) => {
  refreshSubscribers.push(callback);
};

// 请求拦截器
instance.interceptors.request.use(
  (config) => {
    const userStore = useUserStore();
    const token = userStore.token;

    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }

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

// 响应拦截器
instance.interceptors.response.use(
  (response) => response.data,
  async (error) => {
    const { config, response } = error;
    const userStore = useUserStore();

    if (response && response.status === 401) {
      // 如果刷新token请求失败,直接登出
      if (config.url.includes("/auth/refresh")) {
        await handleLogout();
        return Promise.reject(new Error("登录已失效"));
      }

      // 如果没有正在刷新token,开始刷新
      if (!isRefreshing) {
        isRefreshing = true;
        try {
          const refreshResult = await refreshToken();
          if (refreshResult) {
            const newToken = userStore.token;
            onRefreshed(newToken);
            config.headers.Authorization = `Bearer ${newToken}`;
            return instance(config);
          } else {
            await handleLogout();
            return Promise.reject(new Error("登录已失效"));
          }
        } finally {
          isRefreshing = false;
        }
      }

      // 返回一个Promise,将请求加入等待队列
      return new Promise((resolve) => {
        addSubscriber((token) => {
          config.headers.Authorization = `Bearer ${token}`;
          resolve(instance(config));
        });
      });
    }

    console.error("请求错误:", response.data.msg || "请求错误");
    return Promise.reject(error);
  }
);

// 处理登出
const handleLogout = async () => {
  const userStore = useUserStore();
  const pageRoute = usePageRoute();
  const fullPagePath = pageRoute.getCurrentFullPagePath();
  localStorage.setItem("fullPage", fullPagePath);

  alert("登录已失效,请重新登录");
  userStore.clearToken();
  userStore.clearUser();
  setTimeout(() => {
    window.location.href = "/pages/login/login";
  }, 2000);
};

// 导出GET请求方法
export const $get = (url, params, options = {}) => {
  return instance.get(url, { params, ...options });
};

// 导出POST请求方法
export const $post = (url, data, options = {}) => {
  return instance.post(url, data, ...options);
};

2.fetch的封装请求

javascript 复制代码
import { apiUrl } from "@/config/global-config.js";
import { useUserStore } from "../stores";
import { usePageRoute } from "@/composable/usePageRoute.js";

// 刷新token的方法
const refreshToken = async () => {
  const userStore = useUserStore();
  try {
    const response = await fetch(`${apiUrl}/auth/refresh`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${userStore.token}`,
      },
    });

    const data = await response.json();
    if (data.code === 200) {
      userStore.setToken(data.data.token);
      return true;
    }
    return false;
  } catch (error) {
    return false;
  }
};

let isRefreshing = false; // 是否正在刷新token
let refreshSubscribers = []; // 存储等待的请求

// 通知所有等待的请求
const onRefreshed = (token) => {
  refreshSubscribers.forEach((callback) => callback(token));
  refreshSubscribers = [];
};

// 添加请求到等待队列
const addSubscriber = (callback) => {
  refreshSubscribers.push(callback);
};

// 处理登出
const handleLogout = async () => {
  const userStore = useUserStore();
  const pageRoute = usePageRoute();
  const fullPagePath = pageRoute.getCurrentFullPagePath();
  localStorage.setItem("fullPage", fullPagePath);

  alert("登录已失效,请重新登录");
  userStore.clearToken();
  userStore.clearUser();
  setTimeout(() => {
    window.location.href = "/pages/login/login";
  }, 2000);
};

// 封装fetch请求
const fetchWithAuth = async (url, options = {}) => {
  const userStore = useUserStore();
  const token = userStore.token;

  const headers = {
    "Content-Type": "application/json",
    ...options.headers,
  };

  if (token) {
    headers.Authorization = `Bearer ${token}`;
  }

  try {
    const response = await fetch(`${apiUrl}${url}`, {
      ...options,
      headers,
    });

    if (response.status === 401) {
      if (!isRefreshing) {
        isRefreshing = true;
        try {
          const refreshResult = await refreshToken();
          if (refreshResult) {
            const newToken = userStore.token;
            onRefreshed(newToken);
            return fetchWithAuth(url, options);
          } else {
            await handleLogout();
            throw new Error("登录已失效");
          }
        } finally {
          isRefreshing = false;
        }
      }

      return new Promise((resolve) => {
        addSubscriber((token) => {
          options.headers.Authorization = `Bearer ${token}`;
          resolve(fetchWithAuth(url, options));
        });
      });
    }

    return response.json();
  } catch (error) {
    console.error("请求错误:", error.message || "请求错误");
    throw error;
  }
};

// 导出GET请求方法
export const $get = (url, params, options = {}) => {
  const queryString = new URLSearchParams(params).toString();
  return fetchWithAuth(`${url}?${queryString}`, { ...options, method: "GET" });
};

// 导出POST请求方法
export const $post = (url, data, options = {}) => {
  return fetchWithAuth(url, {
    ...options,
    method: "POST",
    body: JSON.stringify(data),
  });
};
相关推荐
mldong3 小时前
引擎从不发一条消息:jeeflow 的两类扩展点与消息模块的分工
java·架构
君顾13 小时前
智慧零售实战指南:从技术架构到落地方案全解析
java·开发语言·零售
zhanghe6874 小时前
es的密码带有特殊字符,导出
java
梦曦i4 小时前
@meng-xi/create-uni-app vs unibest:轻量脚手架与重型框架的定位之争
前端·uni-app
平头哥技术团队4 小时前
Day 10 | 工欲善其事:VS Code 配置与项目归档
android·开发语言·前端·javascript·html·交互
pnoker4 小时前
IoT DC3 概念解读:把设备抽象成一套语义模板——位号、指令、事件与面向智能体的设备建模
java·人工智能·物联网·iot·dc3
my_realmy4 小时前
Java SE 基础学习笔记(一):面向对象、继承多态、抽象接口与异常(JDK 8)
java·多线程·并发··生产者消费者模式
乌恩大侠5 小时前
GH200 新增 NVMe SSD 分区、格式化与挂载完整流程
运维·服务器·前端
天远数科5 小时前
风险治理实战:基于天远车信盟出险构建自动化理赔核保流水线
java·网络·人工智能·自动化
yume_sibai5 小时前
Element Plus 数据展示组件完全指南(15个核心组件)
前端·javascript·vue.js