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

Node.js/Express错误捕获最佳实践:MongoDB连接场景的正确实现

Hey there! Let's walk through the best practices for handling MongoDB connection errors in your Express app to keep it running reliably, without relying on repetitive if/else blocks. First, let's fix a quick issue in your connection string: it should be mongodb://localhost/db (three slashes, not two) — that's a common typo that causes connection failures right off the bat.

1. Use Promise/Async-Await with Express Error Handling Middleware

Modern MongoDB drivers support Promises, so we can ditch callback-based code for async/await, which makes error handling cleaner. The key here is to leverage Express's built-in error-handling middleware to centralize error logic instead of handling it in every route or connection callback.

First, create a dedicated database connection module (e.g., db.js) to separate connection logic from your routes:

const { MongoClient } = require('mongodb');
const DB_URI = "mongodb://localhost/db";
let dbInstance;

// Connect to MongoDB and cache the connection
async function connectToDB() {
  try {
    const client = await MongoClient.connect(DB_URI);
    dbInstance = client.db();
    console.log("✅ Connected to MongoDB successfully");
    return dbInstance;
  } catch (err) {
    console.error("❌ MongoDB connection failed:", err);
    // Optional: Add retry logic here if you want the app to retry connecting
    // setTimeout(connectToDB, 5000);
    throw err; // Propagate the error to let Express handle it
  }
}

// Get the cached DB instance
function getDB() {
  if (!dbInstance) {
    throw new Error("Database not connected yet — call connectToDB() first");
  }
  return dbInstance;
}

module.exports = { connectToDB, getDB };

Then, in your main Express app file (e.g., app.js), initialize the DB connection before starting the server, and set up a global error handler:

const express = require('express');
const { connectToDB, getDB } = require('./db');
const app = express();

// Initialize DB connection and start server
(async () => {
  try {
    await connectToDB();
    app.listen(3000, () => console.log("🚀 Server running on port 3000"));
  } catch (err) {
    console.error("❌ Failed to start server: DB connection error", err);
    process.exit(1); // Exit if we can't connect to the database (optional, based on your needs)
  }
})();

// Example route using the DB
app.get('/api/data', async (req, res, next) => {
  try {
    const db = getDB();
    const data = await db.collection('your-collection').find().toArray();
    res.json(data);
  } catch (err) {
    next(err); // Pass the error to the global handler
  }
});

// Express error-handling middleware (must have 4 parameters)
app.use((err, req, res, next) => {
  console.error("Request error:", err);
  // Return user-friendly error based on environment
  const statusCode = err.statusCode || 500;
  res.status(statusCode).json({
    message: process.env.NODE_ENV === 'production' 
      ? "Internal Server Error" 
      : err.message,
    error: process.env.NODE_ENV === 'production' 
      ? {} 
      : err.stack
  });
});

2. Add Global Unhandled Error Listeners

Even with careful try/catch handling, there might be uncaught exceptions or unhandled promise rejections. Add these listeners to your main app file to prevent silent crashes:

// Catch unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
  console.error("Unhandled Rejection at:", promise, "Reason:", reason);
  // Optional: Clean up resources (e.g., close DB connections) before exiting
});

// Catch uncaught synchronous exceptions
process.on('uncaughtException', (err) => {
  console.error("Uncaught Exception:", err);
  // Exit the process safely — Node.js becomes unstable after uncaught exceptions
  process.exit(1);
});

Why This Is Better Than If/Else

  • Centralized error handling: No need to write if (err) in every callback or route — all errors flow to one middleware.
  • Cleaner, more readable code: Async/await makes asynchronous logic look synchronous, avoiding callback hell.
  • Resilience: You can add retry logic for DB connections, and global listeners catch edge cases that might crash your app.
  • Separation of concerns: DB connection logic is isolated, making it easier to test and maintain.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:28:42