axios 在React中刷新页面后,API请求未收到访问令牌

mbyulnm0  于 2022-12-18  发布在  iOS
关注(0)|答案(1)|浏览(128)

我正在使用Pet-finder API制作一个React应用程序,我将访问令牌存储在一个上下文中,当我呈现一个特定的动物页面时,它呈现得很好(大多数时候,假设是因为同样的问题),但是当我刷新页面时,它抛出了status: 401的axios错误,API文档将其称为Access was denied due to invalid credentials。当我检查头时,它包含Authorization: "undefined undefined",其中令牌类型和令牌本身应该是。
我发现的部分修复是将token添加到useEffect的依赖性数组中,我使用该数组来进行请求,但在刷新时错误仍然会弹出到控制台中,并且数据会立即加载。此外,这是我在渲染后立即请求的唯一页面(可能与此问题有关)。
TokenContext.jsx

const TokenContext = createContext();

export const TokenProvider = ({ children }) => {
  const [token, setToken] = useState({});
  let location = useLocation();

  const fetchToken = async () => {
    await axios
      .get("http://localhost:3001/fetchToken")
      .then((res) => {
        const newToken = {
          token: res.data.access_token,
          tokenType: res.data.token_type,
          expires: new Date().getTime() + res.data.expires_in * 1000,
        };

        localStorage.setItem("token", JSON.stringify(newToken));
      })
      .catch((error) => {
        console.log(error);
      });
  };

  useEffect(() => {
    const foundToken = JSON.parse(localStorage.getItem("token"));

    if (!foundToken || token.expires - new Date().getTime() < 10) {
      fetchToken();
    } else {
      setToken(foundToken);
    }
  }, [location.pathname]);

  return (
    <TokenContext.Provider value={{ token }}>{children}</TokenContext.Provider>
  );
};

export default TokenContext;

Pet.jsx

const Pet = () => {
  const { id } = useParams();
  const { token } = useContext(TokenContext);
  const [isLoading, setIsLoading] = useState(false);
  const [pet, setPet] = useState({});

  useEffect(() => {
    setIsLoading(true);

    petFinderApi
      .get(`/animals/${id}`, {
        headers: {
          Authorization: `${token.tokenType} ${token.token}`,
        },
      })
      .then((res) => {
        setPet(res.data.animal);
        setIsLoading(false);
      })
      .catch((error) => {
        console.log(error);
      });
  }, [token]);

  if (!pet) {
    return (
      isLoading ?? (
        //Spinner renders here
      )
    );
  } else {
    return (
//Stuff will render here
)
  }
};

export default Pet;
uqcuzwp8

uqcuzwp81#

令牌最初为空对象:
const [token, setToken] = useState({});
当您在后台获取令牌时,令牌值将传递给TokenContext
<TokenContext.Provider value={{ token }}>{children}</TokenContext.Provider>
在第一次呈现期间,仍将执行以下useEffect

useEffect(() => {
// ...
}, [token]); // {}

尝试添加一个检查,以查看标记是否为useEffect中的未定义/空对象?

useEffect(() => {
    setIsLoading(true);
    
    if(token && Object.keys(token).length !== 0){
       // grab a pet
    }
  }, [token]);

而不是写作

if (!pet) {
    return (
      isLoading ?? (
        //Spinner renders here
      )
    );


也可以使用React.Suspense显示微调器。
例如,在

import { Suspense } from 'react';

//... other code

return (
   <Suspense fallback={<MySpinner />}>
      <MyComponentToDisplayWhenPetIsFetched pet={pet} />
   </Suspense>
);

本教程很好地解释了Suspense

相关问题