教程 hono tutorial

请求验证

TypeScript 类型不能验证真实请求。公开 API 必须在运行时检查 JSON、查询参数、表单数据和路径参数。

Hono 自带轻量 validator,也常与 @hono/zod-validator、Zod 搭配使用。

使用 validator

ts
import { validator } from 'hono/validator'

app.post(
  '/posts',
  validator('json', (value, c) => {
    const title = value['title']

    if (typeof title !== 'string' || title.trim() === '') {
      return c.json({ message: 'title is required' }, 400)
    }

    return {
      title: title.trim(),
    }
  }),
  (c) => {
    const input = c.req.valid('json')
    return c.json({ id: 1, title: input.title }, 201)
  },
)

验证通过后,通过 c.req.valid('json') 读取整理后的值。

使用 Zod Validator

先安装:

bash
pnpm add zod @hono/zod-validator

定义 schema:

ts
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'

const createPostSchema = z.object({
  title: z.string().min(1).max(100),
  body: z.string().min(1),
})

app.post('/posts', zValidator('json', createPostSchema), (c) => {
  const input = c.req.valid('json')
  return c.json({ id: crypto.randomUUID(), ...input }, 201)
})

验证查询参数

ts
const listQuerySchema = z.object({
  page: z.coerce.number().int().positive().default(1),
  pageSize: z.coerce.number().int().min(1).max(100).default(20),
})

app.get('/posts', zValidator('query', listQuerySchema), (c) => {
  const query = c.req.valid('query')
  return c.json(query)
})

查询参数本来都是字符串,z.coerce.number() 可以把字符串转为数字。

验证表单

ts
const contactSchema = z.object({
  email: z.string().email(),
  message: z.string().min(1).max(1000),
})

app.post('/contact', zValidator('form', contactSchema), (c) => {
  const form = c.req.valid('form')
  return c.json({ received: true, email: form.email })
})

验证建议

  • 所有外部输入都要验证,包括请求体、查询参数、路径参数和 Header。
  • 验证器返回的对象应尽量是业务代码真正需要的结构。
  • 错误响应要稳定,方便前端展示和测试断言。
  • 不要把数据库层错误当作输入验证。输入错误应该在进入业务逻辑之前处理。