import type { VextErrorMiddleware } from "../../types/middleware.js"; import type { VextResponseConfig, VextLogger } from "../../types/app.js"; import type { VextInternalHooks } from "../../types/hooks.js"; /** * DevOverlayFn — Dev 错误覆盖层渲染函数 * * 接受原始错误,返回 HTML 字符串。 * 由 dev-bootstrap 在注入时通过闭包绑定 projectRoot 和 overlayOptions。 * error-handler.ts 不直接依赖 error-overlay.ts(避免生产 bundle 引入 dev 代码)。 */ export type DevOverlayFn = (err: unknown) => string; /** * createErrorHandler — 全局错误处理中间件工厂 * * 内置中间件 #6(通过 adapter.registerErrorHandler() 注册),职责: * 捕获中间件链中抛出的所有错误,按类型格式化为统一的 JSON 错误响应。 * * 三层错误匹配规则(按优先级): * * 1. VextValidationError(422 Validation Failed) * 由 validate 中间件在 schema 校验失败时抛出。 * 响应:{ code: 422, message: 'Validation failed', errors: [...], requestId } * errors 数组包含每个字段的错误描述:[{ field: 'email', message: '...' }] * * 2. HttpError(4xx / 5xx 业务错误) * 由 app.throw() 或用户代码 throw new HttpError(...) 抛出。 * 响应:{ code, message, requestId } * code 取值优先级:err.code(业务错误码)> err.status(HTTP 状态码) * 这意味着如果用户传入了业务码(如 10001),响应的 code 就是 10001; * 否则 code 等于 HTTP 状态码(如 404)。 * * 3. 未知错误(500 Internal Server Error) * 所有不属于上述两类的错误(运行时异常、第三方库异常等)。 * 响应:{ code: 500, message: 'Internal Server Error', requestId } * 生产环境(hideInternalErrors = true)隐藏 stack trace, * 开发环境(hideInternalErrors = false)附带 stack 供调试。 * * Dev 错误覆盖层(可选 devOverlay 参数): * 当 devOverlay 已注入且请求 Accept 包含 'text/html' 时, * 返回 HTML 错误覆盖层而非 JSON。适用于浏览器直接访问出错路由的场景。 * devOverlay 渲染失败时,自动降级到 JSON 处理。 * * 工厂函数设计(Q21): * 使用工厂模式 createErrorHandler(config) 而非直接引用 app.config, * 原因是错误处理器需要持有 config 引用但不应直接依赖 app 对象。 * 工厂函数在 bootstrap 时调用一次,返回的闭包通过闭包变量持有 config, * 解决了作用域和生命周期问题。 * * 注册方式(在 bootstrap 中): * app.adapter.registerErrorHandler( * createErrorHandler(config.response ?? {}, undefined, app.logger) * ) * * 与 rawJson 的关系: * 错误响应始终使用 res.rawJson(),绕过出口包装(response-wrapper)。 * 这确保错误响应格式为 { code, message, requestId } 而非被二次包装为 * { code: 0, data: { code, message, ... }, requestId }。 * * 日志记录(可选 logger 参数): * 当 logger 传入时,error-handler 负责在响应格式决策之前记录日志: * - 未知错误(500):logger.error({ err }, '[uncaught] ...')(含 stack trace) * - HttpError 5xx:logger.error('[http-error] status message') * - HttpError 4xx:logger.warn(...)(需 logErrors.http4xx = true 开启) * - VextValidationError:不记录(客户端输入问题) * 日志记录先于 devOverlay 判断,确保无论响应格式如何日志都可见。 * 不传 logger 时行为与原来完全一致(向后兼容)。 * * @param responseConfig 响应配置(从 VextConfig.response 提取) * @param devOverlay 可选:dev 模式错误覆盖层渲染函数(生产模式不传) * @param logger 可选:VextLogger 实例,传入后自动记录错误日志 * @returns VextErrorMiddleware */ export declare function createErrorHandler(responseConfig: VextResponseConfig, devOverlay?: DevOverlayFn, logger?: VextLogger, hooks?: VextInternalHooks): VextErrorMiddleware;