mongodb 驱动在连接时不会因数据库名不存在或端口配置轻微错误而立即抛出异常——前者因数
据库按需创建,后者因连接超时延迟触发;真正即时报错的是协议非法(如 `moodb://`)等 uri 格式问题。事件监听器也必须在 `connect()` 调用前注册,否则会错过 `connected` 等关键事件。
在使用 Mongoose 连接 MongoDB 时,初学者常对「看似错误却无报错」的现象感到困惑,例如:
这并非 Bug,而是 MongoDB 及其 Node.js 驱动的设计逻辑所致,具体原因如下:
MongoDB 不会预先校验目标数据库是否存在。当首次执行写入操作(如 Model.create())或显式调用 db.createCollection() 时,驱动才会自动创建该数据库。因此,rec-db 在连接阶段只是个“待激活名称”,连接本身(到 MongoDB 服务进程)完全合法,自然不会报错。
270 端口上通常没有 MongoDB 实例监听,但 Mongoose(基于 mongodb 官方驱动)默认启用连接重试与超时机制(默认 connectTimeoutMS=30000ms)。此时连接会持续尝试、最终超时,并以 MongoServerSelectionError 形式在 catch 中抛出——不是不报错,而是延迟报错。你若未设置足够长的超时等待或未捕获 connect() 的 Promise,就可能误以为“没异常”。
URI 解析由驱动底层完成。moodb:// 不符合 mongodb:// 或 mongodb+srv:// 的标准协议格式,驱动在初始化阶段即抛出 MongoInvalidArgumentError,导致 connect() 同步失败,Promise 立即 reject,从而进入 catch 块。
你观察到 database.once("connected", ...) 未执行,根本原因是:
await mongoose.connect(...); // ← 此行内部已触发 connected 事件
database.once("connected", () => { ... }); // ← 此时事件早已发生,监听器失效✅ 正确做法是:在调用 mongoose.connect() 之前注册监听器,尤其是 connected、error、disconnected 等关键事件:
import mongoose from "mongoose";
// ✅ 1. 先注册事件监听器
mongoose.connection
.once("connected", () => console.log("✅ Database connected"))
.on("error", (err) => console.error("❌ Connection error:", err))
.on("disconnected", () => console.warn("⚠️ Database disconnected"));
// ✅ 2. 再发起连接(注意:connect 返回 Promise,需 await 或 .then)
await mongoose.connect("mongodb://127.0.0.1:27017/recipe-db", {
// 推荐显式配置超时与重连,提升可观测性
connectTimeoutMS: 5000,
serverSelectionTimeoutMS: 5000,
retryWrites: true,
});遵循以上原则,你将更准确地理解 MongoDB 连接生命周期,写出健壮、可维护的数据库初始化逻辑。