将多个异步获取请求链接到服务器时,Await 不起作用

问题描述 投票:0回答:0

在 bakcend 上,我有两个端点用于刷新和验证 jwt 令牌。 在客户端,我想在每个需要授权凭据的请求之前验证并刷新它们。

因此,在用户上下文提供程序中,我创建了用于验证和刷新令牌的异步函数,并创建了将这两者结合起来的函数。

这是我的用户上下文

import { createContext, useState, useEffect } from "react"


const backend_url = process.env.REACT_APP_BACKEND_URL

const UserContext = createContext({})

const UserContextProvider = ({children}) => {
    const [user, setUser] = useState(JSON.parse(localStorage.getItem('tokens')))

    // validate user token
    const tokenIsValid = async () => {
        return await fetch(`${backend_url}/auth/verify`,{
            method: "POST",
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify({token: `${user.access}`})
        })
        .then(response => response.ok)
        .catch(error => console.log(error))
    }

    // refresh token
    const refreshToken = async () => {
        return await fetch(`${backend_url}/auth/refresh`, {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify({refresh: `${user.refresh}`})
        })
        .then(response => {
            if(response.ok){
                return response.json()
            }
            
            throw new Error("refresh Token error")
        })
        .then(data => {
            const _user = {...user, access: data.access}
            setUser({..._user})
            localStorage.setItem('tokens', JSON.stringify({..._user}))
        })
        .catch(error => console.log(error))
    }

    // set params for authFetch
    const getParams = params => {
        return {
            ...params,
            headers: {
                ...params.headers,
                "Authorization": `Bearer ${user.access}`
            }
        }
    }

    // Authorized request. Token is validated, refreshed(if needed) 
    // and used in authorization header during fetch
    const authFetch = async (url, params) => {
        const isValid = await tokenIsValid()
        if (isValid){
            return fetch(url, getParams(params))
        }

        // check if token is refreshable
        try{
            await refreshToken()
            return fetch(url, getParams(params))
        }
        catch(e){
            setUser(null)
            localStorage.removeItem('tokens')
            throw new Error("Refresh token is invalid")
        }
    } 

    return (
        <UserContext.Provider value={{user, setUser, authFetch}}>
            {children}
        </UserContext.Provider>
    )
}

export {UserContext, UserContextProvider}

这是客户端尝试获取用户照片 url 时的使用示例

export default function AuthWidget(){
    const {user, setUser, authFetch} = useContext(UserContext)
    const [userPhoto, setUserPhoto] = useState("")

    const handleAuthorization = response => {
        fetch(`${backend_url}/auth/telegram/widget`, {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(response)
        })
        .then(response => response.json())
        .then(data => {
            setUser(data)
            localStorage.setItem('tokens', JSON.stringify(data))
        })
        .catch(error => console.log(error))
    }

    // set user photo
    useEffect(() => {
        authFetch(`${photo_url}`, {
            method: "GET"
        })
        .then(response => response.json())
        .then(data => setUserPhoto(data.photo_url))
        .catch(error => console.log(error))
    }, [user])

    return (
        <Container fluid className='p-0'>
            {user ? 
                <Link to="/user">
                    <Image src={userPhoto} roundedCircle height="40px"/>
                </Link> 
                : 
                <TelegramLoginButton 
                    className="mt-2"
                    dataOnauth={handleAuthorization} 
                    buttonSize="small" 
                    usePic={false} 
                    botName={process.env.REACT_APP_BOT_NAME}
                />
            }
        </Container>
    )
}

问题在于,当访问令牌过期时,authFetch 不会等待刷新令牌完成。 来自后端的日志:

[27/Jul/2023 17:41:34] "POST /auth/verify HTTP/1.1" 401 65
[27/Jul/2023 17:41:34] "POST /auth/refresh HTTP/1.1" 200 254
Unauthorized: /user/photo
[27/Jul/2023 17:41:34] "GET /user/photo HTTP/1.1" 401 183
[27/Jul/2023 17:41:34] "POST /auth/verify HTTP/1.1" 200 2
[27/Jul/2023 17:41:34] "GET /user/photo HTTP/1.1" 200 80

我该如何解决这个问题?

reactjs react-hooks async.js
© www.soinside.com 2019 - 2024. All rights reserved.