我终于不再在每个 Express 控制器里写 try‑catch(你也应该如此)

发布: (2025年12月25日 GMT+8 09:15)
4 min read
原文: Dev.to

Source: Dev.to

Cover image for I finally stopped writing try-catch in every Express controller (and you should too)

让我们诚实地说一下。我们都讨厌在 Express 中编写错误处理。

你从一个漂亮、简洁的控制器函数开始。它只应该做一件事:注册用户。但现实很快击中你。你需要验证请求体。你需要检查邮箱是否已存在于 MongoDB 中。你需要捕获意外的崩溃。

不知不觉中,你的 5 行函数已经变成了一个 50 行的意大利面怪兽,包裹在巨大的 try/catch 块中。

我过去常常把这段模板代码在项目之间复制粘贴,直到我找到了一种更简洁的方式。最近,我开始使用 ds-express-errors,它真的让后端逻辑的编码重新变得有趣起来。

“旧的我”方法 🍝

// controllers/authController.js
const User = require('../models/User');

exports.register = async (req, res, next) => {
  try {
    // 1. Manually checking for missing fields... boring.
    if (!req.body.email || !req.body.password) {
      return res.status(400).json({ status: 'error', message: 'Missing fields' });
    }

    const newUser = await User.create(req.body);

    res.status(201).json({ success: true, data: newUser });
  } catch (err) {
    // 2. The "Error parsing hell"
    // Is it a validation error? A duplicate key? Who knows?
    if (err.name === 'ValidationError') {
      const msg = Object.values(err.errors).map(val => val.message).join(', ');
      return res.status(400).json({ success: false, message: msg });
    }

    if (err.code === 11000) {
      return res.status(409).json({ success: false, message: 'Email already taken' });
    }

    // 3. Just giving up
    console.error(err);
    res.status(500).json({ success: false, message: 'Server Error' });
  }
};

如果你有 20 个控制器,就会有 20 份相同的 catch 代码块。若要更改错误响应的格式,就必须对所有代码进行重构。

“全新自我”方法 ✨

// controllers/authController.js
const User = require('../models/User');
const { asyncHandler, Errors } = require('ds-express-errors');

// No try‑catch. Just logic.
exports.register = asyncHandler(async (req, res) => {
  const newUser = await User.create(req.body);

  // Need to throw a custom error? Easy.
  if (!newUser) {
    throw Errors.BadRequest('Could not create user');
  }

  res.status(201).json({ success: true, data: newUser });
});

就是这样。

“等等,如果 MongoDB 抛出错误会怎样?”

库的中间件会自动检测到这是一个 Mongoose 错误。

  • Duplicate Key (E11000) → 400 Bad Request,返回 “Duplicate field value entered”。
  • Validation Error → 将你的验证信息合并后返回 400。
  • JWT Error → 401 Unauthorized。

我根本不需要为此写任何 if 语句。

设置极其简单

const express = require('express');
const { errorHandler } = require('ds-express-errors');

const app = express();

// ... define your routes here ...

// Just put this at the END of your middleware chain
app.use(errorHandler);

app.listen(3000, () => console.log('Server is flying 🚀'));

额外奖励:夜间更好地睡眠(优雅关闭)

const { initGlobalHandlers, gracefulHttpClose } = require('ds-express-errors');

const server = app.listen(PORT);

initGlobalHandlers({
  // Wraps the server close method safely
  closeServer: gracefulHttpClose(server),

  // Close your DB connections here
  onShutdown: async () => {
    console.log('Closing DB...');
    await mongoose.disconnect();
  }
});

现在,如果我收到 SIGTERM 或未处理的拒绝,应用程序将在退出前清理它的混乱。

判决

有一百万个错误处理程序,但我坚持使用这个,因为它具有 零依赖 并且开箱即支持 TypeScript。它只会消除我代码中的噪音。

Link:

Back to Blog

相关文章

阅读更多 »

新加入 Dev 社区

大家好,我是 dev 社区的新成员,重新开始我的 coding 之旅。我曾在 2013‑2018 年间编写代码。之后我探索了新的机会,...