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

Node/Express中JWT中间件致MongoDB数据重复写入问题求助

问题分析与解决办法

核心问题根源

  1. 路由未发送响应导致客户端重试:你的/newuser路由处理函数末尾没有返回任何响应(如res.send()/res.json()),请求会一直处于挂起状态,客户端(浏览器/前端)会判定为超时并自动重试,触发两次路由执行,最终写入重复数据。
  2. 中间件异步逻辑不规范:checkUser标记为async但内部使用回调式jwt.verify,虽不直接导致重复,但存在异步逻辑混乱的风险。
  3. 全局中间件挂载方式可能引发重复匹配:app.post('*', checkUser)的写法若配合其他路由中间件,可能出现重复执行的情况。

具体解决步骤

1. 修复路由未响应问题

在/newuser路由处理函数末尾添加响应,结束请求生命周期,避免客户端重试:

// ... 你的原有代码
await user_info.save()
    .then(resp => console.log(resp))
    .catch(err => console.log(err))
await workout_info.save()
    .then(resp => console.log(resp))
    .catch(err => console.log(err))

// 添加响应,终止请求
res.status(201).json({ 
    message: '用户信息和训练计划创建成功',
    user: user_info,
    workout: workout_info
})

2. 优化checkUser中间件的异步逻辑

jwt.verify本身是同步函数,改用try-catch替代回调写法,让代码更清晰且符合async/await规范:

const checkUser = async (req, res, next) => {
    const token = req.cookies.jwt

    if (token) {
        try {
            const decodedToken = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET);
            const user = await User.findById(decodedToken.id);
            res.locals.user = user;
            next();
        } catch (err) {
            res.locals.user = null;
            console.log(err.message);
            next();
        }
    } else {
        res.locals.user = null;
        next();
    }
}

3. 调整全局中间件挂载方式

替换app.post('*', checkUser)为全局挂载,确保中间件仅执行一次:

// 全局挂载,所有请求都会经过该中间件
app.use(checkUser);

// 若仅需对POST请求生效,可改为:
// app.use('*', checkUser);

4. 排查前端重复请求

检查前端代码,确认是否存在重复触发请求的情况(如按钮绑定两次点击事件、axios/fetch被调用两次),修复路由响应后,客户端重试的情况会自然消失。


验证效果

  1. 启用app.use(express.json())并重启服务。
  2. 发送一次POST请求到/newuser。
  3. 控制台只会输出一次res.locals.user.username。
  4. 检查MongoDB,确认仅写入一条user_info和一条routines数据。

内容的提问来源于stack exchange,提问作者Neil Sharma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 19:39:27