ExpressJS如何全局处理500/404/401/403等特定HTTP错误
问题原因
你的错误处理不生效是核心写法不符合Express中间件执行规则导致的:
- 注册顺序错误:Express按照代码从上到下的顺序匹配执行中间件、路由,你把
app.listen写在路由和错误中间件前面,部分场景下会导致请求处理逻辑未加载完成就启动端口监听。 - 误用废弃API:
app.use(app.router)是Express 3的遗留写法,Express 4+版本已内置路由处理逻辑,加这行会打乱中间件执行栈顺序。 - 未覆盖路由不匹配场景:用户访问不存在的路径时,Express不会主动抛出错误,不会进入4参数格式的错误处理中间件,需要在所有路由末尾加兜底逻辑主动抛404错误。
- 错误处理末尾多余调用:你已经向客户端返回响应后再调用
next(err),会触发Express内置默认错误处理器,覆盖已返回的结果。 - 注意:所有业务逻辑里的401、403、500错误,都需要通过
next(错误对象)的方式传递给全局错误中间件,不要在路由里单独写响应逻辑。
修正后完整代码
import express from 'express'; import 'dotenv/config'; //import atlasConnection from './database/mongo-connection.js'; //import erroHandler from './middlewares/error.middleware.js'; //await atlasConnection(); const port = process.env.PORT; const app = express(); // 全局基础中间件要写在路由前面,按需开启 // app.use(express.json()) // app.use(posts); // app.use(users); app.get('/api', (req, res, next) => { res.send('test') }) // 所有路由注册完成后,加无匹配路由兜底 app.use('*', (req, res, next) => { const notFoundErr = new Error('Resource not found'); notFoundErr.status = 404; next(notFoundErr); }) // 全局错误处理中间件,必须写在所有路由、404兜底逻辑后面 app.use(function(err, req, res, next ) { // 开发环境可打印错误日志排查问题,生产环境按需关闭 console.error(err); const statusCode = err.status || 404; const baseRes = { success: false, code: 4001, error: "Resource not found" }; switch (statusCode) { case 500: baseRes.error = "Server Error"; break; case 401: baseRes.code = 2001; baseRes.error = "Unauthorized"; break; case 403: baseRes.code = 2002; baseRes.error = "Forbidden"; break; // 404和其余未知错误统一走默认返回逻辑,无需额外写case } res.status(statusCode).json(baseRes); // 已返回响应,不要再调用next(err) }) // listen必须写在所有中间件、路由注册的最末尾 if (process.env.NODE_ENV !== 'test') { app.listen(port, () => console.log(`Server listening on port ${port}`)); } export default app;
使用说明
- 业务路由里需要抛出401/403/500错误时,直接构造带status属性的Error对象传给next即可,示例:
// 鉴权失败场景示例 app.get('/api/protected', (req, res, next) => { if (!req.headers.authorization) { const unauthErr = new Error('Unauthorized'); unauthErr.status = 401; return next(unauthErr); } // 正常业务逻辑 })
- 异步路由的错误如果是Express 4版本,需要手动catch后传给next,或者引入
express-async-errors包做全局兼容;Express 5版本默认支持异步错误直接传递,无需额外处理。
内容的提问来源于stack exchange,提问作者IMNOTIKE
相关产品推荐
相关产品推荐

