如何在Node.js Express中构建无需逐API加try-catch的集中式错误处理
Node.js 集中式错误处理方案(无需逐接口添加try-catch)
要实现无需在每个API接口中手动写try-catch的集中式错误处理,核心思路是自动捕获异步函数的错误并传递给Express错误中间件,结合自定义错误类来统一响应格式,以下是具体实现步骤:
1. 封装异步错误捕获工具函数
Express 默认不会捕获异步函数中抛出的错误,因此我们需要一个工具函数来包装所有异步路由处理函数,自动捕获错误并传递给next():
// utils/asyncHandler.js const asyncHandler = (fn) => (req, res, next) => { Promise.resolve(fn(req, res, next)).catch(next); }; module.exports = asyncHandler;
使用方式
在路由中直接用这个工具函数包裹异步处理逻辑,无需手动写try-catch:
// routes/api.js const asyncHandler = require('../utils/asyncHandler'); const fetchSomeData = require('../services/dataService'); app.get('/api/users', asyncHandler(async (req, res) => { const users = await fetchSomeData(); res.status(200).json({ data: users }); }));
2. 定义自定义错误类
为了区分不同类型的业务错误(如404、401、403等),建议创建自定义错误类,携带状态码和错误信息:
// errors/HttpError.js class HttpError extends Error { constructor(statusCode, message) { super(message); this.statusCode = statusCode; this.name = 'HttpError'; // 保留错误栈信息,便于调试 Error.captureStackTrace(this, this.constructor); } } module.exports = HttpError;
在业务逻辑中抛错
在服务层或路由中,根据业务场景抛出自定义错误:
// services/dataService.js const HttpError = require('../errors/HttpError'); const db = require('../db'); async function fetchSomeData(userId) { const result = await db.query('SELECT * FROM users WHERE id = ?', [userId]); if (result.length === 0) { throw new HttpError(404, '指定用户不存在'); } return result; }
3. 实现集中式错误处理中间件
完善你已尝试创建的错误中间件,统一处理所有错误并返回标准响应:
// middleware/errorHandler.js const HttpError = require('../errors/HttpError'); const errorHandler = (err, req, res, next) => { // 处理自定义HttpError if (err instanceof HttpError) { return res.status(err.statusCode).json({ success: false, error: { message: err.message, code: err.statusCode } }); } // 处理其他未知错误(如数据库连接错误、语法错误等) console.error('服务器未知错误:', err.stack); res.status(500).json({ success: false, error: { message: '服务器内部错误', code: 500 } }); }; module.exports = errorHandler;
注册错误中间件
注意:必须将错误中间件注册在所有路由和其他中间件之后,确保所有错误都能被捕获:
// app.js const express = require('express'); const errorHandler = require('./middleware/errorHandler'); const apiRoutes = require('./routes/api'); const app = express(); // 注册其他中间件(如express.json()、路由等) app.use(express.json()); app.use('/api', apiRoutes); // 注册错误处理中间件 app.use(errorHandler); app.listen(3000, () => console.log('服务启动在3000端口'));
额外注意事项
- 同步代码中抛出的错误,Express会自动传递给错误中间件,无需额外处理
- 可以扩展自定义错误类,比如
ValidationError、AuthError,在错误中间件中做更细粒度的响应处理 - 生产环境中不要返回详细的错误栈给前端,只返回友好提示;开发环境可以保留栈信息便于调试
内容的提问来源于stack exchange,提问作者Rohith kumar
相关产品推荐
相关产品推荐

