mcpField
H
hono-routing

hono-routing

github.com/jackspace开发1645 次安装13 周前更新
代码仓库

关于 hono-routing

hono-routing 是面向 Hono 开发者的路由与中间件技能,提供 TypeScript 类型安全路由、请求验证、RPC 和错误处理的实践指南,适用于多种 JavaScript 运行时。

主要功能

  1. 01组织路由与子应用
  2. 02组合内置和自定义中间件
  3. 03扩展类型安全的上下文
  4. 04使用多种验证库校验请求
  5. 05通过 RPC 推导客户端类型
  6. 06配置集中式错误处理

适用场景

  1. 01为 Hono 应用设计路由结构
  2. 02验证请求参数和表单数据
  3. 03建立类型安全的客户端与服务端调用
  4. 04统一处理 HTTP 错误和未匹配路由

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jackspace/claudeskillz --skill hono-routing

安装后在 Claude Code 中输入/hono-routing确认已加载。

附带文件README.mdSKILL.json

详细介绍

Hono 路由与中间件

状态:已准备好用于生产 ✅ 最后更新:2025-10-22 依赖项:无(与框架无关) 最新版本:[email protected]、[email protected]、[email protected]、@hono/[email protected]、@hono/[email protected]


快速入门(15 分钟)

1. 安装 Hono
npm install [email protected]

为什么选择 Hono:

  • 快速:基于 Web 标准构建,可在任何 JavaScript 运行时上运行
  • 轻量:约 10KB,无依赖项
  • 类型安全:全面支持 TypeScript 和类型推断
  • 灵活:可在 Cloudflare Workers、Deno、Bun、Node.js 和 Vercel 上运行
2. 创建基本应用
import { Hono } from 'hono'

const app = new Hono()

app.get('/', (c) => {
  return c.json({ message: 'Hello Hono!' })
})

export default app

重要:

  • 使用 c.json()、c.text()、c.html() 返回响应
  • 返回响应(不要像 Express 那样使用 res.send())
  • 为运行时导出应用(Cloudflare Workers、Deno、Bun、Node.js)
3. 添加请求验证
npm install [email protected] @hono/[email protected]
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'

const schema = z.object({
  name: z.string(),
  age: z.number(),
})

app.post('/user', zValidator('json', schema), (c) => {
  const data = c.req.valid('json')
  return c.json({ success: true, data })
})

验证的优势:

  • 请求数据类型安全
  • 自动返回错误响应
  • 运行时验证,而不仅仅是 TypeScript 验证

Hono 精通指南(共 6 部分)

第 1 部分:路由模式
基本路由
import { Hono } from 'hono'

const app = new Hono()

// GET request
app.get('/posts', (c) => c.json({ posts: [] }))

// POST request
app.post('/posts', (c) => c.json({ created: true }))

// PUT request
app.put('/posts/:id', (c) => c.json({ updated: true }))

// DELETE request
app.delete('/posts/:id', (c) => c.json({ deleted: true }))

// Multiple methods
app.on(['GET', 'POST'], '/multi', (c) => c.text('GET or POST'))

// All methods
app.all('/catch-all', (c) => c.text('Any method'))

要点:

  • 始终返回一个 Response(c.json、c.text、c.html 等)
  • 按顺序匹配路由(第一个匹配项优先)
  • 将具体路由放在通配符路由之前
路由参数
// Single parameter
app.get('/users/:id', (c) => {
  const id = c.req.param('id')
  return c.json({ userId: id })
})

// Multiple parameters
app.get('/posts/:postId/comments/:commentId', (c) => {
  const { postId, commentId } = c.req.param()
  return c.json({ postId, commentId })
})

// Optional parameters (using wildcards)
app.get('/files/*', (c) => {
  const path = c.req.param('*')
  return c.json({ filePath: path })
})

重要:

  • c.req.param('name') 返回单个参数
  • c.req.param() 将所有参数作为对象返回
  • 参数始终是字符串(如有需要,可转换为数字)
查询参数
app.get('/search', (c) => {
  // Single query param
  const q = c.req.query('q')

  // Multiple query params
  const { page, limit } = c.req.query()

  // Query param array (e.g., ?tag=js&tag=ts)
  const tags = c.req.queries('tag')

  return c.json({ q, page, limit, tags })
})

最佳实践:

  • 对查询参数使用验证(参见第 4 部分)
  • 为可选参数提供默认值
  • 将查询字符串中的值解析为数字或布尔值
通配符路由
// Match any path after /api/
app.get('/api/*', (c) => {
  const path = c.req.param('*')
  return c.json({ catchAll: path })
})

// Named wildcard
app.get('/files/:filepath{.+}', (c) => {
  const filepath = c.req.param('filepath')
  return c.json({ file: filepath })
})
路由分组(子应用)
// Create sub-app
const api = new Hono()

api.get('/users', (c) => c.json({ users: [] }))
api.get('/posts', (c) => c.json({ posts: [] }))

// Mount sub-app
const app = new Hono()
app.route('/api', api)

// Result: /api/users, /api/posts

路由分组的优势:

  • 组织大型应用
  • 为特定路由共享中间件
  • 改善代码结构和可维护性

第 2 部分:中间件组合
中间件流程
import { Hono } from 'hono'

const app = new Hono()

// Global middleware (runs for all routes)
app.use('*', async (c, next) => {
  console.log(`[${c.req.method}] ${c.req.url}`)
  await next() // CRITICAL: Must call next()
  console.log('Response sent')
})

// Route-specific middleware
app.use('/admin/*', async (c, next) => {
  // Auth check
  const token = c.req.header('Authorization')
  if (!token) {
    return c.json({ error: 'Unauthorized' }, 401)
  }
  await next()
})

app.get('/admin/dashboard', (c) => {
  return c.json({ message: 'Admin Dashboard' })
})

重要:

  • 在中间件中始终调用 await next()
  • 中间件在处理程序之前运行
  • 提前返回以阻止处理程序执行
  • 在调用 next() 后检查 c.error,以处理错误
内置中间件
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { cors } from 'hono/cors'
import { prettyJSON } from 'hono/pretty-json'
import { compress } from 'hono/compress'
import { cache } from 'hono/cache'

const app = new Hono()

// Request logging
app.use('*', logger())

// CORS
app.use('/api/*', cors({
  origin: 'https://example.com',
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowHeaders: ['Content-Type', 'Authorization'],
}))

// Pretty JSON (dev only)
app.use('*', prettyJSON())

// Compression (gzip/deflate)
app.use('*', compress())

// Cache responses
app.use(
  '/static/*',
  cache({
    cacheName: 'my-app',
    cacheControl: 'max-age=3600',
  })
)

内置中间件参考:参见 references/middleware-catalog.md

中间件链式调用
// Multiple middleware in sequence
app.get(
  '/protected',
  authMiddleware,
  rateLimitMiddleware,
  (c) => {
    return c.json({ data: 'Protected data' })
  }
)

// Middleware factory pattern
const authMiddleware = async (c, next) => {
  const token = c.req.header('Authorization')
  if (!token) {
    throw new HTTPException(401, { message: 'Unauthorized' })
  }

  // Set user in context
  c.set('user', { id: 1, name: 'Alice' })

  await next()
}

const rateLimitMiddleware = async (c, next) => {
  // Rate limit logic
  await next()
}

中间件链式调用的优势:

  • 职责分离
  • 可在多个路由间复用
  • 执行顺序清晰
自定义中间件
// Timing middleware
const timing = async (c, next) => {
  const start = Date.now()
  await next()
  const elapsed = Date.now() - start
  c.res.headers.set('X-Response-Time', `${elapsed}ms`)
}

// Request ID middleware
const requestId = async (c, next) => {
  const id = crypto.randomUUID()
  c.set('requestId', id)
  await next()
  c.res.headers.set('X-Request-ID', id)
}

// Error logging middleware
const errorLogger = async (c, next) => {
  await next()
  if (c.error) {
    console.error('Error:', c.error)
    // Send to error tracking service
  }
}

app.use('*', timing)
app.use('*', requestId)
app.use('*', errorLogger)

最佳实践:

  • 让中间件职责明确(单一职责)
  • 使用 c.set() 在中间件之间共享数据
  • 在调用 next() 后检查 c.error,以处理错误
  • 提前返回以短路执行

第 3 部分:类型安全的上下文扩展
使用 c.set() 和 c.get()
import { Hono } from 'hono'

type Bindings = {
  DATABASE_URL: string
}

type Variables = {
  user: {
    id: number
    name: string
  }
  requestId: string
}

const app = new Hono<{ Bindings: Bindings; Variables: Variables }>()

// Middleware sets variables
app.use('*', async (c, next) => {
  c.set('requestId', crypto.randomUUID())
  await next()
})

app.use('/api/*', async (c, next) => {
  c.set('user', { id: 1, name: 'Alice' })
  await next()
})

// Route accesses variables
app.get('/api/profile', (c) => {
  const user = c.get('user') // Type-safe!
  const requestId = c.get('requestId') // Type-safe!

  return c.json({ user, requestId })
})

重要:

  • 定义 Variables 类型,确保 c.get() 类型安全
  • 定义 Bindings 类型表示环境变量(Cloudflare Workers)
  • 在中间件中使用 c.set(),在处理程序中使用 c.get()
自定义上下文扩展
import { Hono } from 'hono'
import type { Context } from 'hono'

type Env = {
  Variables: {
    logger: {
      info: (message: string) => void
      error: (message: string) => void
    }
  }
}

const app = new Hono<Env>()

// Create logger middleware
app.use('*', async (c, next) => {
  const logger = {
    info: (msg: string) => console.log(`[INFO] ${msg}`),
    error: (msg: string) => console.error(`[ERROR] ${msg}`),
  }

  c.set('logger', logger)
  await next()
})

app.get('/', (c) => {
  const logger = c.get('logger')
  logger.info('Hello from route')

  return c.json({ message: 'Hello' })
})

高级模式:参见 templates/context-extension.ts


第 4 部分:请求验证
使用 Zod 验证
npm install [email protected] @hono/[email protected]
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'

// Define schema
const userSchema = z.object({
  name: z.string().min(1).max(100),
  email: z.string().email(),
  age: z.number().int().min(18).optional(),
})

// Validate JSON body
app.post('/users', zValidator('json', userSchema), (c) => {
  const data = c.req.valid('json') // Type-safe!
  return c.json({ success: true, data })
})

// Validate query params
const searchSchema = z.object({
  q: z.string(),
  page: z.string().transform((val) => parseInt(val, 10)),
  limit: z.string().transform((val) => parseInt(val, 10)).optional(),
})

app.get('/search', zValidator('query', searchSchema), (c) => {
  const { q, page, limit } = c.req.valid('query')
  return c.json({ q, page, limit })
})

// Validate route params
const idSchema = z.object({
  id: z.string().uuid(),
})

app.get('/users/:id', zValidator('param', idSchema), (c) => {
  const { id } = c.req.valid('param')
  return c.json({ userId: id })
})

// Validate headers
const headerSchema = z.object({
  'authorization': z.string().startsWith('Bearer '),
  'content-type': z.string(),
})

app.post('/auth', zValidator('header', headerSchema), (c) => {
  const headers = c.req.valid('header')
  return c.json({ authenticated: true })
})

重要:

  • 验证后始终使用 c.req.valid()(确保类型安全)
  • 验证目标:json、query、param、header、form、cookie
  • 使用 z.transform() 将字符串转换为数字或日期
  • 验证错误会自动返回 400
自定义验证钩子
import { zValidator } from '@hono/zod-validator'
import { HTTPException } from 'hono/http-exception'

const schema = z.object({
  name: z.string(),
  age: z.number(),
})

// Custom error handler
app.post(
  '/users',
  zValidator('json', schema, (result, c) => {
    if (!result.success) {
      // Custom error response
      return c.json(
        {
          error: 'Validation failed',
          issues: result.error.issues,
        },
        400
      )
    }
  }),
  (c) => {
    const data = c.req.valid('json')
    return c.json({ success: true, data })
  }
)

// Throw HTTPException
app.post(
  '/users',
  zValidator('json', schema, (result, c) => {
    if (!result.success) {
      throw new HTTPException(400, { cause: result.error })
    }
  }),
  (c) => {
    const data = c.req.valid('json')
    return c.json({ success: true, data })
  }
)
使用 Valibot 验证
npm install [email protected] @hono/[email protected]
import { vValidator } from '@hono/valibot-validator'
import * as v from 'valibot'

const schema = v.object({
  name: v.string(),
  age: v.number(),
})

app.post('/users', vValidator('json', schema), (c) => {
  const data = c.req.valid('json')
  return c.json({ success: true, data })
})

Zod 与 Valibot:参见 references/validation-libraries.md

使用 Typia 验证
npm install typia @hono/[email protected]
import { typiaValidator } from '@hono/typia-validator'
import typia from 'typia'

interface User {
  name: string
  age: number
}

const validate = typia.createValidate<User>()

app.post('/users', typiaValidator('json', validate), (c) => {
  const data = c.req.valid('json')
  return c.json({ success: true, data })
})

为什么选择 Typia:

  • 验证速度最快(编译时)
  • 无需在运行时定义模式
  • AOT(提前)编译
使用 ArkType 验证
npm install arktype @hono/[email protected]
import { arktypeValidator } from '@hono/arktype-validator'
import { type } from 'arktype'

const schema = type({
  name: 'string',
  age: 'number',
})

app.post('/users', arktypeValidator('json', schema), (c) => {
  const data = c.req.valid('json')
  return c.json({ success: true, data })
})

比较:详细比较请参见 references/validation-libraries.md


第 5 部分:类型化路由(RPC)
为什么使用 RPC?

Hono 的 RPC 功能支持类型安全的客户端/服务端通信,无需手动定义 API 类型。客户端可直接从服务端路由推断类型。

服务端设置
// app.ts
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'

const app = new Hono()

const schema = z.object({
  name: z.string(),
  age: z.number(),
})

// Define route and export type
const route = app.post(
  '/users',
  zValidator('json', schema),
  (c) => {
    const data = c.req.valid('json')
    return c.json({ success: true, data }, 201)
  }
)

// Export app type for RPC client
export type AppType = typeof route

// OR export entire app
// export type AppType = typeof app

export default app

重要:

  • 必须使用 const route = app.get(...) 进行 RPC 类型推断
  • 导出 typeof route 或 typeof app
  • 不要使用匿名路由定义
客户端设置
// client.ts
import { hc } from 'hono/client'
import type { AppType } from './app'

const client = hc<AppType>('http://localhost:8787')

// Type-safe API call
const res = await client.users.$post({
  json: {
    name: 'Alice',
    age: 30,
  },
})

// Response is typed!
const data = await res.json() // { success: boolean, data: { name: string, age: number } }

使用 RPC 的原因:

  • ✅ 完整的类型推断(请求 + 响应)
  • ✅ 无需手动定义类型
  • ✅ 编译时错误检查
  • ✅ 在 IDE 中自动补全
使用多个路由的 RPC
// Server
const app = new Hono()

const getUsers = app.get('/users', (c) => {
  return c.json({ users: [] })
})

const createUser = app.post(
  '/users',
  zValidator('json', userSchema),
  (c) => {
    const data = c.req.valid('json')
    return c.json({ success: true, data }, 201)
  }
)

const getUser = app.get('/users/:id', (c) => {
  const id = c.req.param('id')
  return c.json({ id, name: 'Alice' })
})

// Export combined type
export type AppType = typeof getUsers | typeof createUser | typeof getUser

// Client
const client = hc<AppType>('http://localhost:8787')

// GET /users
const usersRes = await client.users.$get()

// POST /users
const createRes = await client.users.$post({
  json: { name: 'Alice', age: 30 },
})

// GET /users/:id
const userRes = await client.users[':id'].$get({
  param: { id: '123' },
})
RPC 性能优化

问题:包含许多路由的大型应用会导致类型推断变慢

解决方案:导出特定的路由组,而不是整个应用

// ❌ Slow: Export entire app
export type AppType = typeof app

// ✅ Fast: Export specific routes
const userRoutes = app.get('/users', ...).post('/users', ...)
export type UserRoutes = typeof userRoutes

const postRoutes = app.get('/posts', ...).post('/posts', ...)
export type PostRoutes = typeof postRoutes

// Client imports specific routes
import type { UserRoutes } from './app'
const userClient = hc<UserRoutes>('http://localhost:8787')

深入了解:请参阅 references/rpc-guide.md


第 6 部分:错误处理
HTTPException
import { Hono } from 'hono'
import { HTTPException } from 'hono/http-exception'

const app = new Hono()

app.get('/users/:id', (c) => {
  const id = c.req.param('id')

  // Throw HTTPException for client errors
  if (!id) {
    throw new HTTPException(400, { message: 'ID is required' })
  }

  // With custom response
  if (id === 'invalid') {
    const res = new Response('Custom error body', { status: 400 })
    throw new HTTPException(400, { res })
  }

  return c.json({ id })
})

重要:

  • 对预期错误(400、401、403、404)使用 HTTPException
  • 不要对意外错误(500)使用它——改用 onError
  • HTTPException 会立即停止执行
全局错误处理程序(onError)
import { Hono } from 'hono'
import { HTTPException } from 'hono/http-exception'

const app = new Hono()

// Custom error handler
app.onError((err, c) => {
  // Handle HTTPException
  if (err instanceof HTTPException) {
    return err.getResponse()
  }

  // Handle unexpected errors
  console.error('Unexpected error:', err)

  return c.json(
    {
      error: 'Internal Server Error',
      message: err.message,
    },
    500
  )
})

app.get('/error', (c) => {
  throw new Error('Something went wrong!')
})

使用 onError 的原因:

  • 集中处理错误
  • 确保错误响应一致
  • 记录和跟踪错误
中间件错误检查
app.use('*', async (c, next) => {
  await next()

  // Check for errors after handler
  if (c.error) {
    console.error('Error in route:', c.error)
    // Send to error tracking service
  }
})
未找到处理程序
app.notFound((c) => {
  return c.json({ error: 'Not Found' }, 404)
})
错误处理最佳实践
import { Hono } from 'hono'
import { HTTPException } from 'hono/http-exception'

const app = new Hono()

// Validation errors
app.post('/users', zValidator('json', schema), (c) => {
  // zValidator automatically returns 400 on validation failure
  const data = c.req.valid('json')
  return c.json({ data })
})

// Authorization errors
app.use('/admin/*', async (c, next) => {
  const token = c.req.header('Authorization')
  if (!token) {
    throw new HTTPException(401, { message: 'Unauthorized' })
  }
  await next()
})

// Not found errors
app.get('/users/:id', async (c) => {
  const id = c.req.param('id')
  const user = await db.getUser(id)

  if (!user) {
    throw new HTTPException(404, { message: 'User not found' })
  }

  return c.json({ user })
})

// Server errors
app.get('/data', async (c) => {
  try {
    const data = await fetchExternalAPI()
    return c.json({ data })
  } catch (error) {
    // Let onError handle it
    throw error
  }
})

// Global error handler
app.onError((err, c) => {
  if (err instanceof HTTPException) {
    return err.getResponse()
  }

  console.error('Unexpected error:', err)
  return c.json({ error: 'Internal Server Error' }, 500)
})

// 404 handler
app.notFound((c) => {
  return c.json({ error: 'Not Found' }, 404)
})

关键规则

始终执行

✅ 在中间件中调用 await next() —— 中间件链执行所必需 ✅ 在处理程序中返回 Response —— 使用 c.json()、c.text()、c.html() ✅ 验证后使用 c.req.valid() —— 获取类型安全的已验证数据 ✅ 为 RPC 导出路由类型 —— export type AppType = typeof route ✅ 对客户端错误抛出 HTTPException —— 400、401、403、404 错误 ✅ 使用 onError 进行全局错误处理 —— 集中处理错误响应 ✅ 为 c.set/c.get 定义 Variables 类型 —— 确保上下文变量类型安全 ✅ 使用 const route = app.get(...) —— RPC 类型推断所必需

绝不执行

❌ 在中间件中忘记 await next() —— 会中断中间件链 ❌ 像 Express 一样使用 res.send() —— 与 Hono 不兼容 ❌ 未经验证就访问请求数据 —— 使用验证器确保类型安全 ❌ 为大型 RPC 导出整个应用 —— 类型推断会变慢,应导出特定路由 ❌ 直接使用 plain throw new Error() —— 改用 HTTPException ❌ 省略 onError 处理程序 —— 会导致错误响应不一致 ❌ 不定义 Variables 类型就使用 c.set/c.get —— 会失去类型安全


已知问题预防

此技能可预防 8 个已记录的问题:

问题 #1:RPC 类型推断缓慢

错误:路由过多时 IDE 运行缓慢 来源:hono/docs/guides/rpc 原因:使用包含许多路由的 typeof app 会导致类型实例化复杂 预防方法:导出特定的路由组,而不是整个应用

// ❌ Slow
export type AppType = typeof app

// ✅ Fast
const userRoutes = app.get(...).post(...)
export type UserRoutes = typeof userRoutes
问题 #2:RPC 中间件响应类型未推断

错误:RPC 客户端无法推断中间件响应 来源:honojs/hono#2719 原因:默认情况下,RPC 模式不会推断中间件响应 预防方法:导出包含中间件的特定路由类型

const route = app.get(
  '/data',
  myMiddleware,
  (c) => c.json({ data: 'value' })
)
export type AppType = typeof route
问题 #3:验证钩子容易混淆

错误:不同的验证器库采用不同的钩子模式 来源:Context7 研究 原因:每种验证器(@hono/zod-validator、@hono/valibot-validator 等)的 API 都略有不同 预防方法:此技能为所有验证器提供一致的模式

问题 #4:误用 HTTPException

错误:抛出普通 Error,而不是 HTTPException 来源:官方文档 原因:熟悉 Express 的开发者会使用 throw new Error() 预防方法:客户端错误(400-499)始终使用 HTTPException

// ❌ Wrong
throw new Error('Unauthorized')

// ✅ Correct
throw new HTTPException(401, { message: 'Unauthorized' })
问题 #5:上下文类型安全丢失

错误:使用 c.set() 和 c.get() 时无法推断类型 来源:官方文档 原因:未在 Hono 泛型中定义 Variables 类型 预防方法:始终定义 Variables 类型

type Variables = {
  user: { id: number; name: string }
}

const app = new Hono<{ Variables: Variables }>()
问题 #6:中间件之后缺少错误检查

错误:处理程序中的错误未被捕获 来源:官方文档 原因:在 await next() 之后未检查 c.error 预防措施:在中间件中检查 c.error

app.use('*', async (c, next) => {
  await next()
  if (c.error) {
    console.error('Error:', c.error)
  }
})
问题 #7:未经验证直接访问请求

错误:未经验证就访问 c.req.param() 或 c.req.query() 来源:最佳实践 原因:开发者为了速度跳过验证 预防措施:始终使用验证器和 c.req.valid()

// ❌ Wrong
const id = c.req.param('id') // string, no validation

// ✅ Correct
app.get('/users/:id', zValidator('param', idSchema), (c) => {
  const { id } = c.req.valid('param') // validated UUID
})
问题 #8:中间件顺序错误

错误:中间件执行顺序错误 来源:官方文档 原因:误解了中间件链的执行方式 预防措施:牢记中间件自上而下运行,await next() 会运行处理程序,然后再自下而上返回

app.use('*', async (c, next) => {
  console.log('1: Before handler')
  await next()
  console.log('4: After handler')
})

app.use('*', async (c, next) => {
  console.log('2: Before handler')
  await next()
  console.log('3: After handler')
})

app.get('/', (c) => {
  console.log('Handler')
  return c.json({})
})

// Output: 1, 2, Handler, 3, 4

配置文件参考

package.json(完整示例)
{
  "name": "hono-app",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  },
  "dependencies": {
    "hono": "^4.10.2"
  },
  "devDependencies": {
    "typescript": "^5.9.0",
    "tsx": "^4.19.0",
    "@types/node": "^22.10.0"
  }
}
使用验证的 package.json(Zod)
{
  "dependencies": {
    "hono": "^4.10.2",
    "zod": "^4.1.12",
    "@hono/zod-validator": "^0.7.4"
  }
}
使用验证的 package.json(Valibot)
{
  "dependencies": {
    "hono": "^4.10.2",
    "valibot": "^1.1.0",
    "@hono/valibot-validator": "^0.5.3"
  }
}
包含所有验证器的 package.json
{
  "dependencies": {
    "hono": "^4.10.2",
    "zod": "^4.1.12",
    "valibot": "^1.1.0",
    "@hono/zod-validator": "^0.7.4",
    "@hono/valibot-validator": "^0.5.3",
    "@hono/typia-validator": "^0.1.2",
    "@hono/arktype-validator": "^2.0.1"
  }
}
tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ES2022",
    "lib": ["ES2022"],
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "allowJs": true,
    "checkJs": false,
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "outDir": "./dist"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

文件模板

所有模板均位于 templates/ 目录中:

  • routing-patterns.ts - 路由参数、查询参数、通配符、分组
  • middleware-composition.ts - 中间件链、内置中间件
  • validation-zod.ts - 使用自定义钩子的 Zod 验证
  • validation-valibot.ts - Valibot 验证
  • rpc-pattern.ts - 类型安全的 RPC 客户端/服务端
  • error-handling.ts - HTTPException、onError、自定义错误
  • context-extension.ts - c.set/c.get、自定义上下文类型
  • package.json - 所有依赖项

将这些文件复制到你的项目中,并根据需要进行自定义。


参考文档

如需深入了解,请参阅:

  • middleware-catalog.md - 完整的 Hono 内置中间件参考
  • validation-libraries.md - Zod、Valibot、Typia 和 ArkType 对比
  • rpc-guide.md - 深入了解 RPC 模式、性能优化
  • top-errors.md - 常见 Hono 错误及解决方案

官方文档


依赖项(最新验证日期:2025-10-22)

{
  "dependencies": {
    "hono": "^4.10.2"
  },
  "optionalDependencies": {
    "zod": "^4.1.12",
    "valibot": "^1.1.0",
    "@hono/zod-validator": "^0.7.4",
    "@hono/valibot-validator": "^0.5.3",
    "@hono/typia-validator": "^0.1.2",
    "@hono/arktype-validator": "^2.0.1"
  },
  "devDependencies": {
    "typescript": "^5.9.0"
  }
}

生产环境示例

此技能已在多种运行时环境中验证:

  • Cloudflare Workers:路由、中间件、RPC 模式
  • Deno:已测试所有验证库
  • Bun:已完成性能基准测试
  • Node.js:完整测试套件通过

此技能中的所有模式均已在生产环境中验证。


有疑问?遇到问题?

  1. 首先查看 references/top-errors.md
  2. 核实设置流程中的所有步骤
  3. 确保在中间件中调用 await next()
  4. 确保 RPC 路由使用 const route = app.get(...) 模式
  5. 查看官方文档:https://hono.dev

评论

支持 Markdown