import type { IncomingMessage } from "node:http"; import type { VextRequest } from "../../types/request.js"; import type { VextApp } from "../../types/app.js"; /** * 预解析的 URL 信息(由 adapter.ts handleRequest 传入,避免重复解析) * * handleRequest 在路由匹配前已执行 indexOf('?') 分割 URL, * 将结果传入 createVextRequest,消除 request.ts 中的冗余解析。 */ export interface ParsedUrl { /** 原始 URL(含 query string),如 /users?page=1 */ rawUrl: string; /** 路径部分(不含 query string),如 /users */ path: string; /** 原始 query string(不含 ?),如 page=1;无 query 时为空字符串 */ queryString: string; } /** * Native Request → VextRequest 转换 * * 直接从 Node.js IncomingMessage 构造 VextRequest,零第三方框架开销。 * 这是 Native Adapter 的核心性能优势之一:跳过 Fastify/Koa/Express 等 * 框架的请求对象包装层,直接操作原生对象。 * * 转换要点: * - query: 懒解析(首次访问时从 URL 解析,结果缓存) * - body: 由 body-parser 中间件后续填充(初始 undefined) * - params: 由 route-core 路由匹配后外部注入 * - headers: 直接使用 IncomingMessage.headers(key 全小写,Node.js 保证) * - requestId: 由 requestId 中间件后续填充(初始空字符串) * - ip: 根据 trustProxy 配置决定从 X-Forwarded-For 或 socket 读取 * - protocol: 根据 trustProxy 配置决定从 X-Forwarded-Proto 或默认值读取 * - onClose: 注册请求关闭钩子,连接断开时触发(通过 req.on('close')) * - valid: 获取 validate 中间件校验后的数据 * - _getRawBody: 从 IncomingMessage 读取原始 body(Buffer)转为字符串, * 供 vext body-parser 中间件使用 * * 性能优化: * - query 使用 getter + 缓存,GET /json 等无 query 场景零开销 * - path 仅做一次 indexOf('?') 分割,避免 new URL() 的完整解析开销 * - headers 直接引用 IncomingMessage.headers,无拷贝 * - _getRawBody 使用 Buffer 拼接 + 缓存,多次调用返回同一字符串 * * 与 Fastify Adapter 的差异: * - Fastify: 通过 Fastify 的 request 对象间接访问(已预解析 query/params) * - Native: 直接操作 IncomingMessage,手动解析(但可懒解析跳过不需要的字段) * - Native 省去了 Fastify 框架本身的对象包装开销 * * @param incoming Node.js IncomingMessage 原始请求对象 * @param app VextApp 实例 * @param params 路由参数(由 route-core 匹配结果提供) * @param parsedUrl 预解析的 URL 信息(由 handleRequest 传入,避免重复 indexOf('?')) * @returns VextRequest 实例(含 _getRawBody 内部方法供 body-parser 使用) * * @see adapters/fastify/request.ts(Fastify Adapter 对应实现) * @see adapters/hono/request.ts(Hono Adapter 对应实现) */ export declare function createVextRequest(incoming: IncomingMessage, app: VextApp, params: Record, parsedUrl: ParsedUrl): VextRequest;