繁体   English   中英

Axios 拦截器在 401 重试时更改 POST 请求的内容类型

[英]Axios interceptor changes the POST request's content type on 401 retry

我无法弄清楚为什么 Axios 在重试时会更改我的请求的内容类型。

我正在创建一个 axios 实例,如下所示(注意全局默认标头):

import axios, { type AxiosInstance } from "axios";
const api: AxiosInstance = axios.create({
  baseURL: "https://localhost:44316/",
});
export default api;

我在我的 vue3 应用程序的各种组件中导入了这个实例。 当我的令牌过期并且检测到 401 时,我使用拦截器刷新我的令牌并重试调用,如下所示(使用等待模式对多个请求进行排队并防止请求多个刷新令牌):

  axios.interceptors.request.use(
    (config) => {
      const authStore = useAuthStore();
      if (!authStore.loggedIn) {
        authStore.setUserFromStorage();
        if (!authStore.loggedIn) {
          return config;
        }
      }
      if (config?.headers && authStore.user.accessToken) {
        config.headers = {
          Authorization: `Bearer ${authStore.user.accessToken}`,
        };
      }
      return config;
    },
    (error) => {
      return Promise.reject(error);
    }
  );
axios.interceptors.response.use(
  (res) => {
    return res;
  },
  async (err) => {
    if (err.response.status === 401 && !err.config._retry) {
      console.log("new token required");
      err.config._retry = true;
      const authStore = useAuthStore();
      if (!authStore.isRefreshing) {
        authStore.isRefreshing = true;

        return new Promise((resolve, reject) => {
          console.log("refreshing token");
          axios
            .post("auth/refreshToken", {
              token: authStore.user?.refreshToken,
            })
            .then((res) => {
              authStore.setUserInfo(res.data as User);
              console.log("refresh token received", err.config, res.data);
              resolve(axios(err.config));
            })
            .catch(() => {
              console.log("refresh token ERROR");
              authStore.logout();
            })
            .finally(() => {
              authStore.isRefreshing = false;
            });
        });
      } else {
        // not the first request, wait for first request to finish
        return new Promise((resolve, reject) => {
          const intervalId = setInterval(() => {
            console.log("refresh token - waiting");
            if (!authStore.isRefreshing) {
              clearInterval(intervalId);
              console.log("refresh token - waiting resolved", err.config);
              resolve(axios(err.config));
            }
          }, 100);
        });
      }
    }
    return Promise.reject(err);
  }
);

但是当 axios 重试发布请求时,它会更改内容类型:

在此处输入图像描述

与原始请求相比(使用内容类型应用程序/json)

在此处输入图像描述

我已经阅读了所有可能找不到的帖子/示例,我对 axios 相对较新,非常感谢任何指导/示例/文档,我靠墙。

为了澄清,我使用了这个模式,因为它是我能够使用许多不同来源组合在一起的最完整的示例,如果有人有更好的模式,我将不胜感激。

这是你的问题...

 config.headers = { Authorization: `Bearer ${authStore.user.accessToken}`, };

您完全覆盖了请求拦截器中的headers object ,除了Authorization之外,它失去了一切。

因为重放的err.config已经将请求体序列化为字符串,删除之前计算的content-type header 意味着客户端必须推断出纯字符串类型。

您应该做的是直接设置新的 header 值,而不覆盖整个 object。

config.headers.Authorization = `Bearer ${authStore.user.accessToken}`;

有关在不涉及间隔或超时的进行中(重新)身份验证请求后面对请求进行排队的方法,请参阅此答案

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM