中间件
VentoStack 中间件遵循洋葱模型(Onion Model),与 Koa 类似。每个中间件可以在请求前后执行逻辑。
type NextFunction = () => Promise<Response>;type Middleware = (ctx: Context, next: NextFunction) => Promise<Response>;每个中间件必须返回 Promise<Response>。调用 await next() 进入下一层,其返回值即为下游的 Response。
import { createApp, requestLogger, errorHandler } from "@ventostack/core";
const app = createApp({ port: 3000 });
// 内置错误处理中间件(建议最先注册)app.use(errorHandler());
// 内置请求日志中间件app.use(requestLogger());
// 自定义中间件示例const timingMiddleware: Middleware = async (ctx, next) => { const start = performance.now(); const response = await next(); const duration = (performance.now() - start).toFixed(2); console.log(`${ctx.method} ${ctx.path} - ${duration}ms`); return response;};
app.use(timingMiddleware);await app.listen();中间件按注册顺序执行,但每个中间件可以在 await next() 前后分别执行逻辑:
// 执行顺序: A前 -> B前 -> C处理 -> B后 -> A后const middlewareA: Middleware = async (ctx, next) => { console.log("A: before"); const response = await next(); console.log("A: after"); return response;};
const middlewareB: Middleware = async (ctx, next) => { console.log("B: before"); const response = await next(); console.log("B: after"); return response;};
app.use(middlewareA);app.use(middlewareB);app.use(async (ctx) => { console.log("C: handle"); return ctx.json({ ok: true });});中间件可以提前返回响应,终止中间件链:
const authMiddleware: Middleware = async (ctx, next) => { const token = ctx.headers.get("authorization"); if (!token) { // 提前返回,后续中间件不会执行 return ctx.json({ error: "Unauthorized" }, 401); } ctx.state.userId = parseToken(token); return next();};requestLogger — 请求日志
Section titled “requestLogger — 请求日志”开箱即用的请求日志中间件,默认输出结构化 JSON:
import { requestLogger } from "@ventostack/core";
// 默认使用 console 输出 JSONapp.use(requestLogger());
// 传入自定义 logger(兼容 @ventostack/observability 的 Logger)app.use(requestLogger({ logger }));
// 静默模式(测试环境禁用日志)app.use(requestLogger({ silent: true }));errorHandler — 全局错误处理
Section titled “errorHandler — 全局错误处理”统一捕获未处理异常,VentoStackError 返回结构化响应,其他错误返回 500 且不暴露内部细节:
import { errorHandler } from "@ventostack/core";
// 建议作为第一个中间件注册,捕获所有后续错误app.use(errorHandler());
// 传入自定义 loggerapp.use(errorHandler({ logger }));
// 自定义生产环境错误消息app.use(errorHandler({ fallbackMessage: "服务暂时不可用" }));配置选项:
includeStackInLog:是否在服务器日志中包含错误堆栈(默认:开发环境 true,生产环境 false)
cors — 跨域处理
Section titled “cors — 跨域处理”import { cors } from "@ventostack/core";
app.use(cors({ origin: "https://example.com" }));
// 允许多个源app.use(cors({ origin: ["https://a.com", "https://b.com"] }));
// 使用函数判断app.use(cors({ origin: (origin) => origin.endsWith(".example.com") }));requestId — 请求 ID
Section titled “requestId — 请求 ID”从请求头读取或自动生成 UUID,并注入到 ctx.state 与响应头中:
import { requestId } from "@ventostack/core";
app.use(requestId()); // 默认 X-Request-Idapp.use(requestId("X-Trace-Id")); // 自定义头名常见中间件示例
Section titled “常见中间件示例”请求体大小限制
Section titled “请求体大小限制”const bodyLimit = (maxBytes: number): Middleware => async (ctx, next) => { const contentLength = ctx.headers.get("content-length"); if (contentLength && Number(contentLength) > maxBytes) { return ctx.json({ error: "Request body too large" }, 413); } return next();};
app.use(bodyLimit(1024 * 1024)); // 1MB静态文件服务 — createStaticMiddleware
Section titled “静态文件服务 — createStaticMiddleware”提供安全的本地文件服务,内置路径遍历防护:
import { createStaticMiddleware } from "@ventostack/core";
app.use(createStaticMiddleware({ root: "/data/uploads", prefix: "/uploads",}));支持选项:root(文件根目录)、prefix(URL 前缀)、allowedExtensions(扩展名白名单)。
其他内置中间件
Section titled “其他内置中间件”@ventostack/core 还提供了以下中间件,详见各自文档页面: