React+Axios调用后端API遭遇401 Unauthorized问题求助
在React应用中调用后端创建店铺的API时,持续收到401 Unauthorized错误。用户登录后已将JWT令牌存入localStorage,发起multipart/form-data类型POST请求时,已在Axios请求头中设置Authorization: Bearer ${token},但认证始终失败。
前端代码
const submitAddStore = async (event) => { event.preventDefault(); const formData = new FormData(); formData.append("pic", pic); formData.append("title", title); formData.append("tele", tele); formData.append("desc", desc); formData.append("location", location); try { if (!title || !tele || !desc || !pic || !location) { Swal.fire({ position: "center", icon: "warning", title: "عذرا", text: "المرجو ملء جميع الحقول ", }); return; } const token = localStorage.getItem("token"); // 从localStorage获取令牌 const result = await axios.post( "http://localhost:5000/api/create-store", formData, { headers: { "content-type": "multipart/form-data", Authorization: `Bearer ${token}`, }, } );
后端代码
app.post( "/api/create-store", protect, upload2.single("pic"), async (req, res) => { const { title, desc, tele, location } = req.body; const picName = req.file.filename; try { const newStore = new store({ title, desc, tele, location, pic: picName, owner: req.user._id, }); await newStore.save(); res.json({ status: "ok" }); } catch (error) { console.error("Error creating store:", error); res.json({ status: "error" }); } } );
认证中间件代码
import jwt from "jsonwebtoken"; import asyncHandler from "express-async-handler"; import User from "../models/useModel.js"; const protect = asyncHandler(async (req, res, next) => { let token; token = req.cookies.jwt; if (token) { console.log("Received Token:", token); try { const decoded = jwt.verify(token, process.env.JWT_SECRET); console.log("Decoded User ID:", decoded.userId); req.user = await User.findById(decoded.userId).select("-password"); console.log("User from Database:", req.user); next(); } catch (error) { console.error(error); res.status(401); throw new Error("Not authorized, token failed"); } } else { res.status(401); throw new Error("Not authorized, no token"); } }); export default protect;
核心原因
后端protect中间件仅从Cookie的jwt字段读取令牌,完全没有处理前端通过Authorization请求头发送的Bearer令牌,导致前端传递的令牌根本没被后端识别,直接触发"无令牌"的401错误。
修复方案
1. 修改后端中间件,支持从Authorization头读取令牌
更新认证逻辑,同时兼容Cookie和请求头两种令牌传递方式:
import jwt from "jsonwebtoken"; import asyncHandler from "express-async-handler"; import User from "../models/useModel.js"; const protect = asyncHandler(async (req, res, next) => { let token; // 优先处理Authorization头中的Bearer令牌 if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) { try { token = req.headers.authorization.split(' ')[1]; // 提取Bearer后的令牌部分 const decoded = jwt.verify(token, process.env.JWT_SECRET); req.user = await User.findById(decoded.userId).select("-password"); next(); return; } catch (error) { console.error(error); res.status(401); throw new Error("Not authorized, token failed"); } } // 兼容原有Cookie读取逻辑 token = req.cookies.jwt; if (token) { try { const decoded = jwt.verify(token, process.env.JWT_SECRET); req.user = await User.findById(decoded.userId).select("-password"); next(); } catch (error) { console.error(error); res.status(401); throw new Error("Not authorized, token failed"); } } else { res.status(401); throw new Error("Not authorized, no token"); } }); export default protect;
2. 前端代码优化(可选)
- 手动设置
content-type: multipart/form-data会丢失浏览器自动生成的boundary标识,导致后端无法正确解析表单数据,建议移除该配置:
const result = await axios.post( "http://localhost:5000/api/create-store", formData, { headers: { Authorization: `Bearer ${token}`, // 仅保留认证头 }, } );
- 可以在请求前打印
token值,确认localStorage.getItem("token")能正确获取到有效令牌。
额外排查点
- 用jwt.io解码令牌,检查
exp字段确认令牌是否过期 - 确认后端
process.env.JWT_SECRET和登录时生成令牌使用的密钥完全一致 - 跨域场景下,确保后端CORS配置允许携带
Authorization请求头
内容的提问来源于stack exchange,提问作者Aben
相关产品推荐
相关产品推荐

