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

让我们诚实地说一下。我们都讨厌在 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: