网站搜索

reactjs - 如何在另一个请求完成之前防止用 Axios 发起请求?


我正在开发一个大型的网络应用程序,它会从不同的地方向服务器发出多个请求。我们使用的令牌有效期为15分钟。这意味着当令牌过期时,会使用刷新令牌来生成一个新的令牌和一个新的刷新令牌。我们正在使用 axios 的拦截器来检测令牌是否已过期。基于此,我们会执行一个请求来生成一个新的令牌。

现在的问题是,在我们发出请求以获取新令牌的期间,所有的 API 调用都会失败!

所以我现在的问题是,是否有可能在某个特定调用完全执行之前阻止发送请求(使用 axios)?

export const runRefreshToken = (errorCallback: () => void): void => {
Axios.interceptors.response.use(
    (response: AxiosResponse<any>): AxiosResponse<any> => {
        return response;
    }, (error: any): any => {
        const original = error.config;
        const loginVerification = !(original.url as string).startsWith("api/login");

        if (error.response && error.response.status === 401 && error.config && loginVerification && !error.config.__retry) {
            return new Promise((resolve): void => {
                original.__retry = true;
                const response = fetch("api/login/refresh-token", { method: 'POST' })
                    .then((): AxiosPromise<any> => {
                        return Axios(original);
                    })
                    .catch((): void => errorCallback())
                resolve(response);
            });
        } else if (error.config.__retry && original.url !== "api/login/verify-authentication") {
            history.push("/login");
        }

        return Promise.reject(error);
    }
);

}

提前感谢

答案#1

这是我在几个团队中遇到过的问题。我们使用的解决方案是在应用的顶层有一个组件,它会发起初始请求,并且在成功之前不会渲染任何子组件。

import React from 'react';
import { useAuthUser } from './hooks';

export const AuthenticateUser = ({ children }) => {
  const { hasError, isLoading, shouldRedirectToLoginPage, handleRedirectToLoginPage } = useAuthUser();

  if (isLoading) {
    return <LoadingPage>;
  }
  if (hasError) {
    return <ErrorPage>;
  }

  return children;
};

钩子文件看起来像

import { userSlice } from 'state/user';
import { useAppDispatch } from 'state/hooks';
import { useEffect } from 'react';
import { useUserDetails } from 'api/userRequests';

export function useUserDetailsProps(): UserDetailsProps {
  const { data, isLoading, error } = useUserDetails();

  const dispatch = useAppDispatch();
  useEffect(() => {
    if (data != null) {
      dispatch(userSlice.actions.authenticatedUserReceived(data));
    }
  }, [data, dispatch]);

  return {
    hasError: !!error,
    isLoading,
    shouldRedirectToLoginPage: !!error && error.response?.status === 401,
    handleRedirectToLoginPage,
  };
}