Imported from zhcndoc/h3 (
AGENTS.md). Install upstream withnpx skills add zhcndoc/h3. Copyright stays with the author.
H3 - 代理指南
H3(读作 /eɪtʃθriː/)是一个为高性能和可移植性打造的极简 HTTP 框架。目前处于 v2 版本——基于 Web 标准原语(Request、Response、URL、Headers)的重大重写。
快速参考
# 安装
corepack enable && pnpm install
# Development
pnpm dev # vitest watch mode
pnpm vitest run <path> # run specific test
pnpm test # full suite (lint + typecheck + coverage)
pnpm build # build with obuild
pnpm lint # oxlint + oxfmt --check (lint + typecheck)
pnpm fmt # automd + oxlint --fix + oxfmt
pnpm bench:node # node benchmarks
pnpm bench:bun # bun benchmarks
架构
核心设计
- 优先 Web 标准:基于原生
Request、Response、URL、Headers - 多运行时支持:Node.js、Bun、Deno、Cloudflare Workers、Service Workers、浏览器
- 极简核心:2 个生产依赖(
rou3路由,srvx服务器抽象) - 基于处理器:可组合的处理器 + 中间件,无重度 class 模式
- 类型安全:全程严格的 TypeScript 泛型推断
关键类
| 类 | 文件 | 作用 |
|---|---|---|
H3 |
src/h3.ts |
主应用类(继承 H3Core),添加路由方法(get/post/put/delete/...) |
H3Event |
src/event.ts |
请求包装——用懒计算属性包装原生 Web Request(URL、上下文) |
HTTPError |
src/error.ts |
带状态码、数据、头部的结构化 HTTP 错误 |
HTTPResponse |
src/response.ts |
灵活的响应构建器 |
请求流程
- 请求经过平台适配器进入(
src/_entries/*.ts) H3.fetch()根据Request创建H3Event- 执行全局
onRequest钩子 - 执行匹配的中间件链(基于路由/方法)
- 路由处理器处理请求并返回值
toResponse()将返回值转换为Response(自动处理 JSON、流、Blob、原始值)- 运行全局
onResponse钩子
项目结构
src/
├── index.ts # 公共 API 导出
├── h3.ts # H3Core + H3 类
├── event.ts # H3Event
├── handler.ts # defineHandler, defineValidatedHandler, etc.
├── middleware.ts # Middleware system
├── response.ts # toResponse, HTTPResponse
├── error.ts # HTTPError
├── adapters.ts # Web/Node 处理器适配器
├── tracing.ts # 跟踪插件(独立入口)
├── types/ # 类型定义
│ ├── h3.ts # 应用类型(H3Config、H3Plugin、H3Route、HTTPMethod)
│ ├── handler.ts # 处理器类型(EventHandler、Middleware)
│ ├── context.ts # H3EventContext
│ ├── route-rules.ts # RouteRules (shared, augmentable: merged rule options on event.context.routeRules)
│ └── _utils.ts # Internal type helpers
├── utils/ # ~30 utility modules (public API)
│ ├── request.ts # getQuery, getRouterParams, getRequestURL, ...
│ ├── response.ts # redirect, noContent, html, iterable, ...
│ ├── body.ts # readBody, readValidatedBody, assertBodySize
│ ├── cookie.ts # getCookie, setCookie, parseCookies, chunked cookies
│ ├── session.ts # getSession, useSession, sealSession, ...
│ ├── auth.ts # requireBasicAuth, basicAuth
│ ├── cors.ts # handleCors, appendCorsHeaders, ...
│ ├── proxy.ts # proxy, proxyRequest, fetchWithEvent
│ ├── ws.ts # defineWebSocketHandler, defineWebSocket
│ ├── json-rpc.ts # defineJsonRpcHandler, defineJsonRpcWebSocketHandler
│ ├── event-stream.ts # createEventStream (SSE)
│ ├── static.ts # serveStatic
│ ├── cache.ts # handleCacheHeaders
│ ├── middleware.ts # onRequest、onResponse、onError、bodyLimit
│ ├── route.ts # defineRoute
│ ├── base.ts # withBase
│ └── internal/ # 内部辅助(不导出)
│ ├── auth.ts, body.ts, cors.ts, encoding.ts 等
│ ├── iron-crypto.ts # 会话封装加密
│ ├── standard-schema.ts # 标准数据校验
│ └── validate.ts
├── rules/ # Route rules (h3/rules subpath entries)
│ ├── index.ts # h3/rules — routeRules middleware, matchers, built-in handlers
│ ├── middleware.ts # routeRules() plug-and-play middleware
│ ├── normalize.ts # normalizeRouteRules (config → runtime rules)
│ ├── match.ts # createRouteRulesMatcher, createMatcherFromFind, memoize
│ ├── merge.ts # mergeMatchedRouteRules (layer merge semantics)
│ ├── types.ts # RouteRuleConfig, NormalizedRouteRules, MatchedRouteRule, RuleHandler
│ ├── cache.ts # h3/rules/cache — ocache-backed cache handler (optional peer)
│ ├── proxy.ts # h3/rules/proxy — proxyRequest-backed proxy handler
│ ├── compiler.ts # h3/rules/compiler — build-time codegen
│ ├── handlers/ # Built-in rule handlers (headers, redirect, cors, cache)
│ ├── compiler/ # Codegen internals (compile, codegen, runtime-rules, options)
│ └── internal/ # key parsing, scope checks, node-key bucketing, pre-merge analysis
├── _entries/ # Platform-specific entry points
│ ├── generic.ts # Web Worker / Browser
│ ├── node.ts # Node.js (adds toNodeHandler)
│ ├── bun.ts # Bun
│ ├── deno.ts # Deno
│ ├── cloudflare.ts # Cloudflare Workers
│ ├── service-worker.ts # Service Workers
│ └── _common.ts # 共享入口工具
└── _deprecated.ts # 弃用导出(v1 兼容)
test/
├── _setup.ts # Test infrastructure (describeMatrix, setupWebTest, setupNodeTest)
├── *.test.ts # ~30 integration test files
├── rules/ # Route rules tests (+ type tests: types.test-d.ts)
├── unit/ # Unit tests (including type tests: types.test-d.ts)
├── bench/ # Benchmarks (mitata)
└── fixture/ # Runtime-specific playground fixtures
代码规范
风格
- 仅 ESM——不使用 CommonJS
- 所有导入路径显式
.ts扩展名 - 不使用桶文件——直接从具体模块导入
- 内部文件用
_前缀(如_deprecated.ts、_entries/、_utils.ts) - 内部辅助放在文件末尾或
utils/internal/ - 文件尽量短小——目标少于 200 行,超出则拆分
- 格式化工具:
oxfmt(无配置,使用默认) - 代码风格检查:
oxlint(启用unicorn,typescript,oxc插件)
命名
- 符号常量使用
k前缀(如kNotFound、kHandled) - 私有/不可枚举属性使用
~前缀 - 真正的私有类字段使用
# - 工厂函数用
define*()命名(如defineHandler、defineMiddleware、defineWebSocketHandler) - 转换函数用
to*()命名(如toResponse、toEventHandler、toWebHandler) - 适配器函数用
from*()命名(如fromWebHandler、fromNodeHandler)
TypeScript
- 严格模式 +
isolatedDeclarations+verbatimModuleSyntax erasableSyntaxOnly: true(不使用枚举和命名空间)- Target/module:
ESNext/NodeNext - Lib:
["ESNext", "WebWorker", "DOM", "DOM.Iterable"] - 大量泛型用于处理器的类型推断
响应处理
处理器直接返回值——无 res.send() 模式:
- 返回
string→ 文本响应 - 返回
object→ JSON 响应 - 返回
Response/HTTPResponse→ 直接响应 - 返回
ReadableStream/Blob/File→ 流响应 - 返回
kNotFound符号 → 404 - 返回
kHandled符号 → 已处理(SSE、WebSocket 等)
测试
框架
- 使用 Vitest v4+ 和 v8 覆盖率
- 矩阵测试:每个测试在
web和node两个模式下均运行
编写测试
import { describeMatrix } from "./_setup.ts";
describeMatrix("feature name", (ctx, { it, expect }) => {
it("does something", async () => {
ctx.app.get("/test", () => "hello");
const res = await ctx.fetch("/test");
expect(await res.text()).toBe("hello");
});
});
主要模式:
- 用
describeMatrix跨运行时测试 ctx.app是每个测试一个新的H3实例(通过beforeEach创建)ctx.fetch处理 web/node 的 URL 解析ctx.errors追踪未处理错误(在afterEach自动断言)- 使用
it.skipIf(ctx.target === "node")跳过特定运行时测试
运行测试
pnpm vitest run test/body.test.ts # 单文件
pnpm vitest run test/unit/ # 单元测试
pnpm dev # 监听模式(所有)
pnpm test # 全套:lint + 类型检查 + 覆盖率
修复 Bug 流程
- 编写回归测试,能重现该 Bug
- 确认测试失败前不改代码
- 修正实现(改动最小化)
- 确认测试通过
- 运行更广泛的测试套件,确保无回归
构建
- obuild with Rolldown bundler
- 6 platform entries +
tracing.tsand the 4rules/*entries as separate entries - Code splitting enabled (
h3-[hash].mjschunks) - Custom plugin strips comments (preserves
#/@annotations) - Output:
dist/_entries/*.mjs+dist/*.d.mts
包导出
h3 → auto-resolved by runtime (deno/bun/workerd/node/default)
h3/node → Node.js runtime (adds toNodeHandler)
h3/bun → Bun runtime
h3/deno → Deno runtime
h3/cloudflare → Cloudflare Workers
h3/service-worker → Service Workers
h3/generic → Universal web standard
h3/tracing → Tracing plugin
h3/rules → Route rules (routeRules middleware, matchers, built-in handlers)
h3/rules/cache → ocache-backed `cache` rule handler (optional `ocache` peer)
h3/rules/proxy → `proxy` rule handler (pulls in proxyRequest)
h3/rules/compiler → Build-time route rules codegen
依赖
| Dep | Purpose |
|---|---|
rou3 |
Route matching engine |
srvx |
Server abstraction (multi-runtime) |
crossws |
WebSocket abstraction (optional peer dep) |
ocache |
Response caching for h3/rules/cache (optional peer dep) |
贡献最佳实践
- 优先使用 Web 标准 API,避免运行时特定 API
- 保持核心极简——新增工具,但不增加核心复杂度
- 使用
describeMatrix跨运行时测试 - 处理器返回值,不直接修改响应对象
- 使用
defineHandler/defineMiddleware保证类型安全