【问题标题】:Axios response interceptor for refreshing token keeps firing刷新令牌的axios响应拦截器不断触发
【发布时间】:2023-03-06 10:19:01
【问题描述】:

逻辑: 每个请求都有一个 JWT 授权标头来验证用户的身份。如果过期,则有一个准备好刷新 JWT 的 cookie 端点。

我正在使用 axios拦截器响应 来检查客户端是否收到 401 来尝试刷新 JWT。 cookie 可能有效或无效。

问题是刷新 JWT 的拦截器永远不会停止触发,我认为我的请求同步有问题。以下是我的代码:

function refreshToken(dispatch) {
  return new Promise((resolve, reject) => {
    instance.put('/auth').then((response) => {
      dispatch({ type: "UPDATE_AUTH", payload: response.data });
      resolve(response);
    })
    .catch((error) => {
      reject(error);
    });
  });
}

instance.interceptors.response.use(
    response => {
      return response;
    },
    err => {
      const error = err.response;
      
      if (error.status === 401 && error.config && !error.config._retry) {
        error.config._retry = true;

        return refreshToken(dispatch).then((resp) => {
          return instance(error.config);
        })
        .catch((e) => {
          return Promise.reject(e);
        });
      }
      return Promise.reject(error);
    }
  );

【问题讨论】:

    标签: javascript reactjs axios


    【解决方案1】:

    如果您有多个并行请求,刷新 JWT 将等于请求数。尝试仅在第一次发送/auth 并阻止下一个请求。您可以使用localStorage 完成此任务。

    let requests = [];
    
    instance.interceptors.response.use(
      response => {
        return response;
      },
      err => {
        const error = err.response;
        
        if (error.status === 401 && error.config && !error.config._retry) {
          requests.push(error.config);
          if (!localStorage.getItem('refresh')) {
            localStorage.setItem('refresh', 'done');
            error.config._retry = true;
    
            return refreshToken(dispatch).then((resp) => {
              localStorage.removeItem('refresh');
              
               const token = getAccessToken();
               requests.map(req => {
                  req.headers.Authorization = `Bearer ${token}`;
                  return instance(req)
               })
            })
            .catch((e) => {
              localStorage.removeItem('refresh');
              return Promise.reject(e);
            });
          }
        } else {
          requests = [];
        }
        return Promise.reject(error);
      }
    );
    

    【讨论】:

    • 检查 /auth 是多余的,使用 localStorage 和 _retry 标志可以解决触发问题。但是现在 dispatch 更新令牌的速度不够快,以至于返回实例(error.config)无法找到令牌。我该如何解决这个问题?
    • 不是Dispatch does not update the token fast,它的工作原理和以前一样,但是现在它只触发一次,instance(error.config); 也会触发一次。如果您想再次调用所有失败的请求,您必须将它们推送到数组中,然后在数组循环中在refreshToken 之后调用instance(error.config);
    • 除了将请求配置推送到数组之外,您还可以执行以下操作 return sleepRequest(1000, instance(error.config);) gist.github.com/edmondburnett/38ed3451de659dc43fa3f24befc0073b
    • 我可以看到 3 个连续请求:第一个 GET /auth 401 (checkAuth)、第二个 PUT /auth 200 (refreshAuth)、第三个 GET /auth 401 (checkAuth)。在第三个(这是请求的重播),我打印出令牌,但它不存在。在 localStorage 中,我可以看到令牌出现,如果我点击浏览器刷新,则用户已登录。
    • 但为了完美,它必须是一个请求 PUT /auth 200 (refreshAuth) 然后请求失败并返回 401 状态码
    猜你喜欢
    • 2021-02-11
    • 2018-06-14
    • 2022-11-03
    • 2020-03-04
    • 2020-01-13
    • 2020-05-12
    • 2019-07-09
    • 1970-01-01
    • 2019-06-14
    相关资源
    最近更新 更多