Axios刷新令牌无限循环 - 多个请求

发布于 2025-01-19 10:22:36 字数 3695 浏览 2 评论 0原文

我查看了有关此问题的其他问题,但无法解决它。我对刷新和访问令牌续订方法有获取请求限制,并且页面中会有多个请求。此外,我的系统中有不同的访问令牌/刷新令牌使用

更新:通过在主实例中创建 axios 实例来处理无限循环问题。现在,我经常遇到请求取消问题并且无法解决。请求后,发出访问令牌请求但被取消。我不知道为什么。

下面你可以看到序列图:

到目前为止,有时它工作得很粗略,一个请求 -> 。 401 访问令牌过期错误 ->在拦截器中更新访问令牌并将其写入 localStorage ->相同的请求解析 200

但大多数情况下都会发生这种情况,并继续访问令牌的 401 循环:

注意:在访问令牌循环开始时,我得到 401,包括“未找到工作人员”错误描述,这意味着在我们的系统更新的令牌不包含在传入的非令牌请求中(过期的令牌包含在标头中)。通常非token请求的401错误的错误描述是“Token过期”。

菜鸟可能会问的问题:一个请求怎么可能只有一个预检和两个 xhr?

这是我的 service.js 代码:

 const sendRequest = async (options) => {
  let requestOptions = {
    ...    // includes the method, data etc.
    if (options.hasOwnProperty("token")) {
        requestOptions.headers = 
          Object.assign(requestOptions.headers, {
          Authorization: RequestOptionConstants.AUTHORIZATION + 
          options.token,
    });
   }
  
 return await axios(
  options.url, //  includes the api url
  requestOptions,    
  axios.interceptors.response.use(
    (response) => {   
      return response;
    },
    async (error) => {
      const originalConfig = error.config;

    if (error.response.status === 401 && !originalConfig._retry) {
      originalConfig._retry = true;

      let refreshToken = JSON.parse(localStorage.getItem("user"))
        .refreshToken;

      // Check for refresh token expiration

      if (jwtDecode(refreshToken).exp < new Date().getTime()) {  
        logout();                  
      }.       

      await axios
        .get(ApiConstants.GET_ACCESS_TOKEN, {
          headers: {
            Authorization:
              "Bearer " +
              JSON.parse(localStorage.getItem("user")).refreshToken,
          },
        })
        .then((res) => {
          if (res.status === 200) {
            const user = JSON.parse(localStorage.getItem("user"));
    

            originalConfig.headers["Authorization"] =
              "Bearer " + res.data.accessToken;

            user.accessToken = res.data.accessToken;

            localStorage.setItem("user", JSON.stringify(user));

            if (res.data.isRefreshTokenInRenewalPeriod) {
              getRefreshToken(originalConfig);
            }

            return axios(originalConfig);
          }
        });
    }

    return Promise.reject(error);
  }
))
   .then(handleResponse, (error) => Promise.reject(error))
   .then((data) => {
    return data;
   });
};

const handleResponse = (response) => {
  const data = response.data;
  if (!data?.result?.success ?? false) {
    const error = data.result;
    return Promise.reject(error);
  }

 return data;
};

function logout() {
  localStorage.removeItem("user");
  window.location.reload();
}

const getRefreshToken = () => {
  axios
    .get(ApiConstants.GET_REFRESH_TOKEN, {
      headers: {
        Authorization:
          "Bearer " + JSON.parse(localStorage.getItem("user")).refreshToken,
      },
    })
    .then((res) => {
      if (res.status === 200) {
        const user = JSON.parse(localStorage.getItem("user"));
        user.refreshToken = res.data.refreshToken;
        localStorage.setItem("user", JSON.stringify(user));
        return axios();
      }
    })
    .catch((error) => {
      console.log(error);
    });
};

实际上,我尝试了 队列方法 中的“返回新 Promise”方法。

队列方法解决了无限循环问题,但这次我在更新刷新令牌时仍然遇到 401 错误,描述为“未找到工作人员”。如何解决异步等待方法的无限循环问题?

已解决:我通过为accessToken和refreshToken定义另外两个axios实例并按顺序调用它们来解决了这个问题。由于保密原因,图像被删除。

I have looked the other questions about this problem but I could not fix it. I have a get request restriction for the refresh and access token renewal methods and there will be multiple requests in a page. Furthermore I have a different access-token/refresh token usage in our system.

UPDATE: Infinite loop issue is handled by creating an axios instance in the main instance. Now, I encounter a request cancellation problem often and couldn't solve it. After a request, access-token request is made but it is cancelled. I don't know why.

Below you can see the sequence diagrams:

So far, sometimes it works cursory, a request -> 401 access token expired error -> renew access token in interceptor and write it to localStorage -> same request resolves 200

But most of the time this happens and it continues with 401 loop for access-token:

Note: At the beginning of the access-token loop I get 401 including the "Staff not found" error description which means that in our system the renewed token is not included in the incoming non-token request(expired token is included in header). Normally the error description of the 401 error for non-token requests is "Token expired".

Possible noob question: How is it possible to have only one preflight and two xhr for a request?

Here is my service.js code:

 const sendRequest = async (options) => {
  let requestOptions = {
    ...    // includes the method, data etc.
    if (options.hasOwnProperty("token")) {
        requestOptions.headers = 
          Object.assign(requestOptions.headers, {
          Authorization: RequestOptionConstants.AUTHORIZATION + 
          options.token,
    });
   }
  
 return await axios(
  options.url, //  includes the api url
  requestOptions,    
  axios.interceptors.response.use(
    (response) => {   
      return response;
    },
    async (error) => {
      const originalConfig = error.config;

    if (error.response.status === 401 && !originalConfig._retry) {
      originalConfig._retry = true;

      let refreshToken = JSON.parse(localStorage.getItem("user"))
        .refreshToken;

      // Check for refresh token expiration

      if (jwtDecode(refreshToken).exp < new Date().getTime()) {  
        logout();                  
      }.       

      await axios
        .get(ApiConstants.GET_ACCESS_TOKEN, {
          headers: {
            Authorization:
              "Bearer " +
              JSON.parse(localStorage.getItem("user")).refreshToken,
          },
        })
        .then((res) => {
          if (res.status === 200) {
            const user = JSON.parse(localStorage.getItem("user"));
    

            originalConfig.headers["Authorization"] =
              "Bearer " + res.data.accessToken;

            user.accessToken = res.data.accessToken;

            localStorage.setItem("user", JSON.stringify(user));

            if (res.data.isRefreshTokenInRenewalPeriod) {
              getRefreshToken(originalConfig);
            }

            return axios(originalConfig);
          }
        });
    }

    return Promise.reject(error);
  }
))
   .then(handleResponse, (error) => Promise.reject(error))
   .then((data) => {
    return data;
   });
};

const handleResponse = (response) => {
  const data = response.data;
  if (!data?.result?.success ?? false) {
    const error = data.result;
    return Promise.reject(error);
  }

 return data;
};

function logout() {
  localStorage.removeItem("user");
  window.location.reload();
}

const getRefreshToken = () => {
  axios
    .get(ApiConstants.GET_REFRESH_TOKEN, {
      headers: {
        Authorization:
          "Bearer " + JSON.parse(localStorage.getItem("user")).refreshToken,
      },
    })
    .then((res) => {
      if (res.status === 200) {
        const user = JSON.parse(localStorage.getItem("user"));
        user.refreshToken = res.data.refreshToken;
        localStorage.setItem("user", JSON.stringify(user));
        return axios();
      }
    })
    .catch((error) => {
      console.log(error);
    });
};

Actually I tried "return new Promise" approach from Queue approach .

The Queue approach solved the infinite loop problem but I still encounter a 401 error with description 'staff not found' while renewing the refresh token this time. How can I solve the infinite loop problem of the async await approach?

SOLVED: I solved this problem with defining two other axios instances for accessToken and refreshToken and calling them in a sequence. Images are deleted because of the confidentiality.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

北凤男飞 2025-01-26 10:22:36

您是否尝试过Axios.Interceptors.Response.eject()?当API拨打并在此之后重新启用API时,它将有助于禁用拦截器。例子:

if (error.response.status === 401 && !originalConfig._retry) {
  originalConfig._retry = true;

  **// Add axios interceptors eject to avoid loop
  axios.interceptors.response.eject();**

  let refreshToken = JSON.parse(localStorage.getItem("user"))
    .refreshToken;

  // Check for refresh token expiration

  if (jwtDecode(refreshToken).exp < new Date().getTime()) {  
    logout();                  
  }
....

Have you tried with axios.interceptors.response.eject() yet? It will help disable the interceptor when API called and re-enable it after. Example:

if (error.response.status === 401 && !originalConfig._retry) {
  originalConfig._retry = true;

  **// Add axios interceptors eject to avoid loop
  axios.interceptors.response.eject();**

  let refreshToken = JSON.parse(localStorage.getItem("user"))
    .refreshToken;

  // Check for refresh token expiration

  if (jwtDecode(refreshToken).exp < new Date().getTime()) {  
    logout();                  
  }
....
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文