用户提交的数据永远不可信。少一个字段、类型不对、格式错误,这些情况每天都在发生。
手动校验长这样:
01app.post('/users', async (c) => {02const body = await c.req.json()0304if (!body.name || typeof body.name !== 'string') {05return c.json({ error: 'name is required' }, 400)06}07if (!body.email || typeof body.email !== 'string') {08return c.json({ error: 'email is required' }, 400)09}10if (!body.email.includes('@')) {11return c.json({ error: 'invalid email' }, 400)12}1314// 终于可以写业务逻辑了...15})
问题很明显:又丑又容易漏,字段一多就失控。而且校验完之后,TypeScript 依然不知道 body 的类型是什么,你还得手动断言。
Hono + Zod 的方案:用 schema 声明数据结构,校验和类型推导一步到位。
什么是 schema
如果你第一次接触后端校验,可以先把 schema 理解成一份数据规则说明书。它不是实际的数据,而是用来描述「什么样的数据才算合法」
比如下面这段数据:
1{2"name": "Alice",3"email": "alice@example.com"4}
它对应的 schema 想表达的是:
name 这个字段必须存在name 必须是字符串email 这个字段必须存在email 必须是合法邮箱格式也就是说,schema 回答的不是「数据是什么」,而是「数据应该长什么样」
在没有 schema 的时候,这些规则通常散落在很多 if 判断里;有了 schema,这些规则就被集中写到一个地方,代码会更清楚。
用 Zod 写出来就是这样:
1const createUserSchema = z.object({2name: z.string().min(1),3email: z.string().email(),4})
这段 schema 可以直接读成自然语言:
z.object({...})name 是字符串,而且不能为空email 是字符串,而且必须符合邮箱格式所以后面你看到 schema 这个词时,不要把它想得太玄。你就把它当成一份「输入数据的规则定义」就行