使用Axios请求拦截器(interceptors.request)刷新JWT令牌-一次多个请求问题

时间:2020-10-14 19:48:29

标签: javascript vue.js axios vuex

我正在使用以下代码拦截Axios中的每个HTTP调用,以通过在JWT令牌过期时刷新JWT令牌来保持用户登录状态:

const { token } = window.localStorage;

const axiosInstance = axios.create({
    baseURL: process.env.VUE_APP_API_ENDPOINT,
    withCredentials: false,
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json",
      Authorization: token && token.length > 0 ? `Bearer ${token}` : ""
    }
  });

axiosInstance.interceptors.request.use(request => {
    if (request.url.endsWith("refresh")) {  // prevent infinite loop
      return request;
    }

const { expiryDate } = window.localStorage;
const currentTimestamp = Math.round(new Date().getTime() / 1000);

if (expiryDate && currentTimestamp >= expiryDate) {
  console.log("token expired.");

  return store
    .dispatch("auth/refreshToken")  // refreshToken action will place the token in localStorage.token
    .then(() => {
      const newToken = window.localStorage.token; 

      request.headers.Authorization = `Bearer ${newToken}`;

      return Promise.resolve(request);
    })
    .catch(() => Promise.resolve(request));
}
console.log("token not expired.");

return request;

});

在我在页面加载时添加更多请求之前,这种方法一直工作良好,每个请求都试图刷新令牌,从而导致后端出现错误。我该如何解决这个问题?我进行了很多搜索,但是找到的所有解决方案都是针对interceptors.response like this one的,我想使用interceptors.request,因为登录是可选的,如果用户登录,则不会有401响应尚未登录。

编辑:根据下面用户28的回答,代码已更改为:

axiosInstance.interceptors.request.use(async config => {
    if (config.url.endsWith("refresh")) {
      // if we are making a refresh token call, return it to prevent infinite loop
      return config;
    }

    await axiosInstance.refreshingToken;

    const { expiryDate } = window.localStorage; // token expiry date

    const currentTimestamp = Math.round(new Date().getTime() / 1000);

    if (expiryDate && currentTimestamp >= expiryDate) {
      axiosInstance.refreshingToken = store.dispatch("auth/refreshToken"); // this will update the token in localstorage
      await axiosInstance.refreshingToken;
    }

    const { token } = window.localStorage; // grab the token from localstorage

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

    return config;
  });

1 个答案:

答案 0 :(得分:1)

您需要一个全局变量来确定是否必须等待。最简单的方法是将其分配给axios实例。

示例代码:

axios.interceptors.request.use(async config => {
  if (isRefreshTokenRequest) {
    return config
  }

  if (axios.refreshingToken) {
    await axios.refreshingToken
  }

  if (isTokenExpired) {
    axios.refreshingToken = store.dispatch('auth/refreshToken')
    await axios.refreshingToken
  }

  // set authorization header

  return config
})