React调用Node.js后端接口遇401未授权问题求助
问题:React请求接口返回401未授权,登录后TOKEN需刷新页面才显示
从数据库获取订单数据时遇到401(Unauthorized)错误,该接口在Postman中可正常调用,但React项目中存在以下问题:
- 登录后控制台打印TOKEN为undefined
- 刷新页面后才能看到正确的TOKEN值
相关代码
Order.jsx(React组件)
import { userRequest } from "../../requestMethods"; import { useEffect, useState } from "react"; const [orders, setOrders] = useState([]); useEffect(() => { const getOrders= async () => { try { const res = await userRequest.get("orders"); setOrders(res.data); } catch {} }; getOrders(); }, []); console.log(orders);
requestMethods.js(Axios配置文件)
import axios from "axios"; const BASE_URL = "http://localhost:5000/api/"; const user = JSON.parse(localStorage.getItem("persist:root"))?.user; const currentUser = user && JSON.parse(user).currentUser; const TOKEN = currentUser?.accessToken; console.log(TOKEN); export const publicRequest = axios.create({ baseURL: BASE_URL, }); export const userRequest = axios.create({ baseURL: BASE_URL, header: { token: `Bearer ${TOKEN}` }, });
order.js(Node.js后端路由)
const Order = require("../models/Order"); const { verifyToken, verifyTokenAndAuthorization, verifyTokenAndAdmin, } = require("./verifyToken"); const router = require("express").Router(); router.get("/", verifyTokenAndAdmin, async (req, res) => { try { const orders = await Order.find(); res.status(200).json(orders); } catch (err) { res.status(500).json(err); } });
问题原因分析
- TOKEN初始化时机问题:
requestMethods.js中的TOKEN是在模块加载时计算的,登录后localStorage更新,但模块不会重新执行,因此TOKEN始终是初始的undefined,只有刷新页面后模块重新加载,才能拿到最新的TOKEN。 - Axios配置错误:
userRequest中的header拼写错误,应为复数headers,导致请求头未正确携带TOKEN。 - 请求发起过早:登录后
localStorage还未完成写入,useEffect就已发起请求,此时TOKEN还未生成。
解决方案
1. 修正Axios配置,改用请求拦截器动态获取TOKEN
修改requestMethods.js,每次请求前从localStorage读取最新TOKEN,避免模块初始化时的静态值问题:
import axios from "axios"; const BASE_URL = "http://localhost:5000/api/"; export const publicRequest = axios.create({ baseURL: BASE_URL, }); export const userRequest = axios.create({ baseURL: BASE_URL, }); // 添加请求拦截器,每次请求前注入最新TOKEN userRequest.interceptors.request.use((config) => { const user = JSON.parse(localStorage.getItem("persist:root"))?.user; const currentUser = user && JSON.parse(user).currentUser; const token = currentUser?.accessToken; if (token) { // 修正headers拼写,正确设置请求头 config.headers.token = `Bearer ${token}`; } return config; });
2. 调整请求发起时机,确保TOKEN已存在
修改Order.jsx中的useEffect,先检查TOKEN是否存在,不存在则延迟重试(或结合登录状态监听):
import { userRequest } from "../../requestMethods"; import { useEffect, useState } from "react"; const Orders = () => { const [orders, setOrders] = useState([]); const getOrders = async () => { try { const res = await userRequest.get("orders"); setOrders(res.data); } catch (err) { console.error("获取订单失败:", err); } }; useEffect(() => { const checkTokenAndFetch = () => { const user = JSON.parse(localStorage.getItem("persist:root"))?.user; const currentUser = user && JSON.parse(user).currentUser; if (currentUser?.accessToken) { getOrders(); } else { // 刚登录时可能localStorage未更新,延迟500ms重试 setTimeout(checkTokenAndFetch, 500); } }; checkTokenAndFetch(); }, []); console.log(orders); return <div>{/* 订单渲染内容 */}</div>; }; export default Orders;
3. 验证后端中间件逻辑
确保verifyToken.js中正确解析Bearer格式的TOKEN:
const jwt = require("jsonwebtoken"); const verifyToken = (req, res, next) => { const authHeader = req.headers.token; if (authHeader) { // 分割Bearer和token部分 const token = authHeader.split(" ")[1]; jwt.verify(token, process.env.JWT_SEC, (err, user) => { if (err) return res.status(403).json("Token无效"); req.user = user; next(); }); } else { return res.status(401).json("未授权,请携带TOKEN"); } }; const verifyTokenAndAdmin = (req, res, next) => { verifyToken(req, res, () => { if (req.user.isAdmin) { next(); } else { res.status(403).json("无管理员权限"); } }); }; module.exports = { verifyToken, verifyTokenAndAdmin };
内容的提问来源于stack exchange,提问作者Herkis
相关产品推荐
相关产品推荐

