You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何不使用Ajax/jQuery等待异步函数执行完成?JWT验证问题

问题

前端验证JWT时,登录获取token的代码如下:

.then((response) => {
    if(response.data.token) {
        localStorage.setItem('token', response.data.token);
        localStorage.setItem('user', response.data.user);
        console.log("Auth: ", auth);

随后调用validateToken函数验证token:

const validateToken = () => {
    Axios.get("https://xx.xxx.xx.xx:xxxx/checkAuth", {
        headers: {"access-token": localStorage.token}
    }).then((response) => {
        setAuth(response.data);
    })
};

该函数会从后端获取响应并存入response.data,但在登录逻辑中调用validateToken后,后续代码会在该函数执行完成前就运行:

const validateToken = () => {
    Axios.get("https://xx.xxx.xx.xx:xxxx/checkAuth", {
        headers: {"access-token": localStorage.token}
    }).then((response) => {
        localStorage.authState = response.data;
    })
};

const handleSubmit = async (e) => {
    e.preventDefault();
    const login = () => {
        Axios.post("https://xx.xxx.xx.xx:xxxx/login", {
            email: email,
            password: pwd
        }).then((response) => {
            if(response.data.token) {
                localStorage.setItem('token', response.data.token);
                localStorage.setItem('user', response.data.user);
                validateToken();                                   // 此处调用后,后续代码直接执行
                // 需要在validateToken执行完成后,再执行成功/失败逻辑
            } else {
                if(response.data.message === "401") {
                    setErrMsg('Missing Username or Password.');
                } else if(response.data.message === "402") {
                    setErrMsg("User doesn't exist.");
                } else {
                    setErrMsg('No Server Response');
                }
            }
        })
        .catch(function (error) {
            if (error.response) {
                console.log("Error: ", error.response.data);
            }
        });

尝试将响应存入localStorage或变量,判断结果执行不同逻辑但无效,例如:

validateToken();
console.log(localStorage.AuthState); // 总是返回undefined

想知道如何不使用Ajax或jQuery,等待validateToken函数执行完成后再执行后续逻辑?

解决方案

核心问题是validateToken内部的Axios请求是异步操作,当前函数没有返回Promise,导致无法等待其执行完成。只需改造函数并利用Promise特性处理即可:

1. 让validateToken返回Promise

修改validateToken,使其返回Axios请求的Promise,同时修正localStorage的使用方式(localStorage仅支持存储字符串,对象需序列化):

const validateToken = () => {
    // 返回Axios请求的Promise,供后续等待
    return Axios.get("https://xx.xxx.xx.xx:xxxx/checkAuth", {
        headers: {"access-token": localStorage.token}
    }).then((response) => {
        const authState = response.data;
        // 正确存储对象到localStorage
        localStorage.setItem('authState', JSON.stringify(authState));
        return authState; // 将验证结果返回,供后续逻辑使用
    }).catch(error => {
        // 捕获验证失败的错误,便于后续处理
        console.error("Token验证失败:", error);
        throw error; // 抛出错误,让调用方可以捕获
    });
};

2. 在登录逻辑中等待validateToken完成

根据代码风格,有两种实现方式:

方式一:使用async/await(代码更简洁清晰)

因为handleSubmit已经标记为async,可以直接在内部使用await等待异步操作完成:

const handleSubmit = async (e) => {
    e.preventDefault();
    try {
        const response = await Axios.post("https://xx.xxx.xx.xx:xxxx/login", {
            email: email,
            password: pwd
        });
        if(response.data.token) {
            localStorage.setItem('token', response.data.token);
            // 序列化user对象后存储
            localStorage.setItem('user', JSON.stringify(response.data.user));
            try {
                // 等待validateToken执行完成
                const authState = await validateToken();
                // 验证成功后的逻辑:比如跳转首页、更新页面状态等
                console.log("Token验证成功:", authState);
            } catch (error) {
                // 验证失败后的逻辑:比如提示错误、清除token等
                setErrMsg("Token验证失败,请重新登录");
                localStorage.removeItem('token');
            }
        } else {
            // 登录返回无token的处理逻辑
            if(response.data.message === "401") {
                setErrMsg('缺少用户名或密码');
            } else if(response.data.message === "402") {
                setErrMsg("用户不存在");
            } else {
                setErrMsg('服务器无响应');
            }
        }
    } catch (error) {
        if (error.response) {
            console.log("登录错误: ", error.response.data);
            setErrMsg("登录失败,请检查账号密码");
        }
    }
};

方式二:使用.then()链式调用

如果不想用async/await,可以在登录的.then()链中继续调用validateToken:

const handleSubmit = (e) => {
    e.preventDefault();
    Axios.post("https://xx.xxx.xx.xx:xxxx/login", {
        email: email,
        password: pwd
    }).then((response) => {
        if(response.data.token) {
            localStorage.setItem('token', response.data.token);
            localStorage.setItem('user', JSON.stringify(response.data.user));
            // 链式调用validateToken,将Promise传递下去
            return validateToken();
        } else {
            // 处理无token情况,返回rejected Promise进入catch
            if(response.data.message === "401") {
                setErrMsg('缺少用户名或密码');
            } else if(response.data.message === "402") {
                setErrMsg("用户不存在");
            } else {
                setErrMsg('服务器无响应');
            }
            return Promise.reject(new Error("登录返回无token"));
        }
    }).then(authState => {
        // Token验证成功后的逻辑
        console.log("Token验证成功:", authState);
    }).catch(error => {
        // 捕获登录或验证过程中的所有错误
        if (error.response) {
            console.log("错误: ", error.response.data);
        } else {
            console.error(error.message);
        }
        setErrMsg("操作失败,请重试");
    });
};

3. 原代码无效的原因

  • Axios请求是异步操作,调用validateToken()后代码会直接往下执行,不会等待请求完成,所以console.log(localStorage.AuthState)会先执行,此时请求还未返回,自然是undefined。
  • 直接赋值localStorage.authState不符合localStorage的API规范,必须使用setItem和getItem方法,且存储对象时需要用JSON.stringify序列化,读取时用JSON.parse解析。

内容的提问来源于stack exchange,提问作者npatrik30

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 06:12:43