lang
lang/javascript/middleware/error-middleware.md
medium
javascript-error-middleware
Express 错误中间件模板。Use when 写 JavaScript 代码 / 评审涉及 `error-middleware` 的 PR。
error middlewarenext(err)错误中间误中间件中间件模
paths
*.js
JS · Express 错误中间件
规则
Express 错误中间件签名是 4 参数 (err, req, res, next),必须放在所有路由之后。
import express from "express";
const app = express();
// 路由
app.get("/api/users", async (req, res, next) => {
try { ... }
catch (err) { next(err); }
});
// 错误中间件 — 放最后
app.use((err, req, res, next) => {
const code = err.code || 500;
const msg = err.message || "internal error";
console.error(`[err] ${req.method} ${req.url}`, err);
res.status(code).json({ success: false, msg, code });
});
业务异常 vs 系统异常
class ApiError extends Error {
constructor(msg, code = 400) {
super(msg);
this.code = code;
}
}
// 业务异常
throw new ApiError("配额不足", 403);
// 中间件按类型分别处理
app.use((err, req, res, next) => {
if (err instanceof ApiError) {
return res.status(err.code).json({ msg: err.message });
}
console.error(err);
res.status(500).json({ msg: "服务繁忙" });
});
async handler 包装器
const wrap = fn => (req, res, next) =>
Promise.resolve(fn(req, res, next)).catch(next);
app.get("/api/users", wrap(async (req, res) => {
const users = await listUsers();
res.json(users);
}));
自检
- [ ] 错误中间件签名
(err, req, res, next)4 参数? - [ ] 位置在所有路由之后?
- [ ] 业务异常用
ApiError子类? - [ ] async handler 用 wrap 包装或 try/catch + next?