错误处理
VentoStack 提供了一套完整的错误类型层级,方便在路由和中间件中抛出语义明确的错误。
内置错误类型
Section titled “内置错误类型”import { VentoStackError, // 基类 ClientError, // 4xx 错误基类 ServerError, // 5xx 错误基类 NotFoundError, // 404 ValidationError, // 400 UnauthorizedError, // 401 ForbiddenError, // 403} from "@ventostack/core";VentoStackError├── ClientError (4xx)│ ├── NotFoundError (404)│ ├── ValidationError (400)│ ├── UnauthorizedError (401)│ └── ForbiddenError (403)└── ServerError (5xx)import { NotFoundError, ValidationError, UnauthorizedError } from "@ventostack/core";
router.get("/users/:id<int>", async (ctx) => { const user = await db.query(UserModel).where("id", "=", ctx.params.id).get();
if (!user) { throw new NotFoundError("用户不存在"); }
return ctx.json(user);});
router.post("/users", defineRouteConfig({ body: { email: { type: "string", required: true }, },}), async (ctx) => { if (!ctx.body.email.includes("@")) { throw new ValidationError("邮箱格式无效", { field: "email" }); }
const user = await createUser(ctx.body as { email: string }); return ctx.json(user, 201);});全局错误处理中间件
Section titled “全局错误处理中间件”建议在应用入口注册全局错误处理中间件:
import { errorHandler } from "@ventostack/core";
const app = createApp({ port: 3000 });
// 建议作为第一个中间件注册,捕获所有后续错误app.use(errorHandler());
// 传入自定义 loggerapp.use(errorHandler({ logger }));
// 静默模式(测试环境禁用日志)app.use(errorHandler({ silent: true }));
// errorHandler 配置选项:// - silent — 是否静默模式(不输出日志)// - logger — 自定义 Logger 实例// - includeStackInLog — 是否在日志中包含错误堆栈;默认非生产环境为 true,生产环境为 false。// 生产环境建议保持默认(不记录堆栈),以防止内部路径和模块结构泄露。如果需要自定义错误处理逻辑,也可以手动实现:
import { VentoStackError, ClientError, ServerError, ValidationError } from "@ventostack/core";import type { Middleware } from "@ventostack/core";
const customErrorHandler: Middleware = async (ctx, next) => { try { await next(); } catch (err) { if (err instanceof VentoStackError) { return ctx.json( { error: err.message, code: err.code, ...(err instanceof ValidationError ? { details: err.details } : {}) }, err.code ); }
// 未预期的错误 console.error("Unhandled error:", err); return ctx.json({ error: "内部服务器错误" }, 500); }};errorHandler 中间件统一捕获未处理异常:
VentoStackError返回结构化响应(包含errorCode和message)- 其他错误返回 500,且不暴露内部错误细节
自定义错误类型
Section titled “自定义错误类型”import { ClientError } from "@ventostack/core";
class PaymentRequiredError extends ClientError { constructor(message: string) { super(message, 402, "PAYMENT_REQUIRED"); }}
class RateLimitError extends ClientError { constructor(retryAfter: number) { super("请求过于频繁,请稍后重试", 429, "RATE_LIMIT_EXCEEDED"); this.retryAfter = retryAfter; }
readonly retryAfter: number;}
// 使用router.post("/checkout", async (ctx) => { const user = ctx.state.user; if (!user.hasPlan) { throw new PaymentRequiredError("需要升级到付费计划"); } // ...});错误类构造参数
Section titled “错误类构造参数”// VentoStackError 基类new VentoStackError(message: string, statusCode: number, errorCode: string)
// 预定义错误new NotFoundError(message?: string) // 404, "NOT_FOUND"new UnauthorizedError(message?: string) // 401, "UNAUTHORIZED"new ForbiddenError(message?: string) // 403, "FORBIDDEN"new ValidationError(message: string, details?: Record<string, unknown>) // 400, "VALIDATION_ERROR"new ClientError(message?: string, code?: number, errorCode?: string) // 400, "CLIENT_ERROR"new ServerError(message?: string, code?: number, errorCode?: string) // 500, "SERVER_ERROR"