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

如何在Express请求头中传递JWT Token?重定向带Header失败

问题分析与解决方案

为什么重定向带不了自定义请求头

浏览器处理3xx重定向时,会发起全新的GET请求,这个请求不会自动携带之前响应里设置的自定义请求头,而且res.redirect()的第二个参数是给模板渲染传值用的,根本不会放到请求头里——所以你之前的尝试都没法实现需求。

可行解决方案

方案1:用Cookie存Token(推荐,更安全)

Cookie会自动在后续所有同域请求中携带,完美适配后端验证的场景。

修改login.js的登录成功逻辑:

if(passCompare == true){
    const id = userId[0].id
    const token = jwt.sign({ id }, process.env.SECRET, {
        expiresIn: 3600
    })
    // 设置Cookie,httpOnly防止前端JS读取,降低XSS风险
    res.cookie('x-access-token', token, { 
        httpOnly: true, 
        maxAge: 3600 * 1000, // 和Token过期时间保持一致
        secure: process.env.NODE_ENV === 'production' // 生产环境用HTTPS时开启
    })
    return res.status(200).redirect('/index')
}

然后修改验证中间件verifyJWT,从Cookie里取Token:

verifyJWT(req, res, next){
    // 从Cookie获取Token
    const token = req.cookies['x-access-token'];
    
    if(!token) {
        return res.status(400).render('login')
    }
    jwt.verify(token, process.env.SECRET, (err, decoded) =>{
        if(err){
            console.log(err)
            // 验证失败清除无效Cookie
            res.clearCookie('x-access-token')
            return res.status(300).render('login')
        }
        req.userId = decoded.id
        next()
    })
}

注意:要在server.js里引入cookie-parser中间件,否则req.cookies无法使用:

const cookieParser = require('cookie-parser')
// 放在其他中间件之前
server.use(cookieParser())

方案2:渲染页面时传Token,前端存后手动携带

如果不想用Cookie,可以登录成功后直接渲染index页面,把Token传给模板,前端存在本地存储,后续AJAX请求手动加请求头。

修改login.js的登录成功逻辑:

if(passCompare == true){
    const id = userId[0].id
    const token = jwt.sign({ id }, process.env.SECRET, {
        expiresIn: 3600
    })
    // 直接渲染index页面并传递Token
    return res.render('index', { token })
}

在index.ejs模板里加脚本存储Token:

<script>
    // 把Token存在localStorage
    localStorage.setItem('token', '<%= token %>');
    // 后续AJAX请求示例
    fetch('/your-api-path', {
        method: 'GET',
        headers: {
            'x-access-token': localStorage.getItem('token')
        }
    })
</script>

这种方式适合需要前端主动控制Token的场景,但要注意XSS风险,尽量配合其他防护措施。

额外优化点

  • 登录逻辑里if(userId == '')判断有误,User.findUserId返回的是数组,空数组不等于空字符串,改成if(!userId || userId.length === 0)才对
  • 错误处理可以更友好,比如用res.render('login', { error: '邮箱无效' })代替send(new Error),让用户在页面看到提示
  • 你把bcrypt拼成了bycrypt,虽然可能是笔误,但建议修正避免依赖问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:01:58