Node.js Express搭配MongoDB时async场景下router.post无法触发问题
问题根因分析
- 混淆了路由注册逻辑和请求处理逻辑:
pushToDB函数内的router.post只是完成POST路由的回调注册操作,本身是同步执行的,不会等到请求进入时才执行完毕,你将它放在await后面毫无意义。 - MongoDB连接被提前关闭:
await pushToDB(client)会立刻执行完成,紧接着触发finally代码块关闭数据库连接,后续POST请求进入时,数据库连接已经被销毁,自然无法正常处理。你贴的可运行同步版本没有写finally关闭连接的逻辑,所以连接一直保持才能正常响应。 - 路由回调没有返回响应:你原来的POST路由回调中执行完插入逻辑后,没有调用
res.send()/res.json()等方法给前端返回响应,会导致前端请求一直处于pending状态,看起来就像路由没有被触发。 - 缺失请求体解析中间件:如果没有配置
express.json()中间件,jQuery ajax提交的JSON格式POST请求体无法被解析,req.body会是undefined,也会导致逻辑异常。
修复后的正确代码
const express = require('express'); const router = express.Router(); const { MongoClient } = require('mongodb'); const uri = "mongodb endpoint"; const client = new MongoClient(uri); // 服务启动时一次性初始化数据库连接 async function initDB() { await client.connect(); console.log('Connected to MongoDB'); } // 注册POST路由,仅当请求进入时才执行插入逻辑 router.post('/', async (req, res, next) => { try { const result = await client.db('user').collection('notes').insertOne(req.body); console.log(`Results ${ result.insertedId }`); // 必须给前端返回响应 res.json({ code: 0, msg: '插入成功', insertId: result.insertedId }); } catch (err) { next(err); // 透传错误到全局错误处理中间件 } }); // 服务启动逻辑 async function startServer() { try { await initDB(); const app = express(); // 必须加这个中间件解析JSON格式的POST请求体 app.use(express.json()); // 按你实际需求调整路由挂载路径 app.use('/your/route/prefix', router); // 启动端口监听,保持服务运行 app.listen(3000, () => { console.log('服务启动成功,监听3000端口'); }); } catch (err) { console.error('服务启动失败', err); await client.close(); process.exit(1); } } startServer().catch(console.error);
异步中间件的正确用法
你之前写的asyncMiddleware可用来统一捕获异步路由的错误,无需每个路由都写try/catch,用法如下:
const asyncMiddleware = fn => (req, res, next) => { Promise.resolve(fn(req, res, next)).catch(next); }; router.post('/', asyncMiddleware(async (req, res) => { const result = await client.db('user').collection('notes').insertOne(req.body); res.json({ code: 0, insertId: result.insertedId }); }));
内容的提问来源于stack exchange,提问作者Stacky
相关产品推荐
相关产品推荐

