
当 JWT 认证中间件未校验请求是否携带 token Cookie 时,若客户端未发送 cookie,jwt.verify() 不会执行回调,导致响应未被发送,Fetch 请求永久 pending。本文提供完整修复方案与最佳实践。
当 jwt 认证中间件未校验请求是否携带 token cookie 时,若客户端未发送 cookie,`jwt.verify()` 不会执行回调,导致响应未被发送,fetch 请求永久 pending。本文提供完整修复方案与最佳实践。
在基于 JWT 的 Cookie 认证流程中,一个常见但隐蔽的陷阱是:忽略对 req.cookies.token 是否存在的显式判断。如原始代码所示,jwt.verify() 是异步操作,它仅在传入有效字符串时触发回调;而当 req.cookies.token 为 undefined 或空字符串时,jsonwebtoken 库内部不会调用回调函数(也不会抛出同步错误),导致 res.json() 和 res.status() 永远不会执行——服务器端响应被遗漏,前端 Fetch 请求便持续处于 pending 状态,最终超时失败。
✅ 正确做法是在调用 jwt.verify() 前,主动校验 token 是否存在且非空:
import jwt from "jsonwebtoken";
export const isAuthenticated = (req, res) => {
const token = req.cookies?.token;
// ✅ 关键防御:检查 token 是否缺失或为空
if (!token || typeof token !== 'string' || token.trim() === '') {
return res.status(401).json({
ok: false,
message: 'Authentication token is missing or invalid.'
});
}
// ✅ 安全传递 token 进行验证
jwt.verify(token, process.env.SECRET, (err, user) => {
if (err) {
// 常见错误:token 过期、签名不匹配、格式非法等
return res.status(403).json({
ok: false,
message: 'Invalid or expired authentication token.',
error: err.name // 可选:用于调试(生产环境建议隐藏)
});
}
// ✅ 验证成功:返回用户信息(注意:user 是解码后的 payload,不含密码等敏感字段)
res.status(200).json({ ok: true, user });
});
};
⚠️ 注意事项:
- 不要链式调用 .json().status():res.json() 已自动发送响应并结束请求周期,后续 .status(200) 无效且易引发 Cannot set headers after they are sent 错误。应始终先调用 res.status() 再调用 res.json()。
- Cookie 安全配置需匹配前端环境:若使用 sameSite: 'none' 和 secure: true,则前端必须通过 HTTPS 访问,且跨域请求需设置 credentials: 'include'。
-
前端 Fetch 示例(确保携带 Cookie):
fetch('/api/auth/isAuthenticated', { method: 'GET', credentials: 'include' // ✅ 必须启用,否则浏览器不发送 Cookie }) .then(res => { if (res.ok) return res.json(); throw new Error(`HTTP ${res.status}`); }) .then(data => console.log('Auth OK:', data)) .catch(err => console.error('Auth failed:', err)); - 日志辅助排查:开发阶段可在中间件开头添加 console.log('Token received:', token),快速确认 Cookie 是否抵达服务端。
总结:JWT Cookie 认证的健壮性始于对输入的严格守门。永远假设客户端可能发送任意(或无)凭证,并在解码前完成存在性与有效性校验。这一原则不仅解决 pending 问题,更是防范未授权访问与服务端异常的基础防线。











