使用Passport.js+EJS跳转报错:手动访问正常,登录重定向失败
问题分析与解决
核心问题
- 请求体编码不匹配:你用
fetch直接传递JavaScript对象作为请求体,但后端配置的express.urlencoded只能解析application/x-www-form-urlencoded格式的表单数据,导致Passport无法获取用户名和密码,验证流程异常。 - Fetch重定向处理冲突:Passport的
successRedirect/failureRedirect会返回3xx重定向响应,fetch会自动跟随重定向并获取目标页面的HTML内容,但前端尝试用response.json()解析HTML,必然抛出语法错误。
解决方案
1. 修正前端请求体格式
将请求体转换为URLSearchParams格式,匹配后端的解析规则:
const response = await fetch("/login", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: new URLSearchParams({ [username.id]: usernameValue, [password.id]: passwordValue, }), })
2. 调整后端验证逻辑,返回JSON响应
放弃Passport的自动重定向,改用自定义回调返回JSON,让前端控制页面跳转:
app.post("/login", (req, res, next) => { passport.authenticate("local", (err, user, info) => { if (err) return res.status(500).json({ error: err.message }); if (!user) return res.status(401).json({ error: info?.message || "登录失败" }); req.login(user, (loginErr) => { if (loginErr) return res.status(500).json({ error: loginErr.message }); return res.json({ id: user.id, href: "/home" }); }); })(req, res, next); });
3. 保留原有前端跳转逻辑
你前端代码中根据返回的href跳转的逻辑可以保留,现在能正确接收后端的JSON响应,不会再出现解析错误。
为什么手动访问正常?
手动在地址栏输入localhost:3000/home是直接发送GET请求,触发后端的res.render("home")直接渲染EJS模板,和登录的POST请求流程完全独立,因此不受Passport验证逻辑影响。
内容的提问来源于stack exchange,提问作者anata0
相关产品推荐
相关产品推荐

