Fastify 入门

定位

Fastify 的核心是用 JSON Schema 定义请求和响应,换取两个好处:请求校验自动完成,序列化速度更快(它用 schema 编译出序列化函数,比 JSON.stringify 快得多)。

它适合「对吞吐量有要求、愿意多写点声明」的团队。

安装

npm init -y
npm install fastify

最小示例

const fastify = require('fastify')({ logger: true })

// 基础路由
fastify.get('/', async () => ({ hello: 'world' }))

// 带 schema 的路由
fastify.post('/users', {
  schema: {
    body: {
      type: 'object',
      required: ['name', 'email'],
      properties: {
        name:  { type: 'string', minLength: 2 },
        email: { type: 'string', format: 'email' },
      },
    },
    response: {
      201: {
        type: 'object',
        properties: {
          id:    { type: 'integer' },
          name:  { type: 'string' },
          email: { type: 'string' },
        },
      },
    },
  },
}, async (req, reply) => {
  // req.body 已经被校验过,类型也对
  const user = await createUser(req.body)
  reply.code(201).send(user)
})

fastify.listen({ port: 3000 })

请求体不合法会自动返回 400,错误格式规范,不需要写校验代码。

核心概念

1. Schema 驱动

Schema 有三个作用,不只是校验:

作用说明
请求校验自动返回 400,带字段级错误信息
序列化加速编译出专用的序列化函数,比 JSON.stringify 快 2-3 倍
文档生成配合 @fastify/swagger 自动产出 OpenAPI

响应 schema 还有一个副作用:它会过滤掉 schema 里没声明的字段。这是防止敏感字段泄漏的好办法,但也会让「我明明返回了这个字段」变成玄学问题。

2. 插件系统

Fastify 的一切都是插件,通过 register 加载:

fastify.register(require('@fastify/cors'))
fastify.register(require('@fastify/jwt'), { secret: 'xxx' })

// 自定义插件
fastify.register(async function (instance, opts) {
  instance.get('/plugin-route', async () => ({ ok: true }))
}, { prefix: '/api' })

3. 封装作用域

这是最容易踩的坑:插件里的装饰器和钩子默认只在该插件作用域内可见。

fastify.register(async (instance) => {
  instance.decorate('db', db)          // 只在这个插件内可见
  instance.get('/a', async () => instance.db)   // ✅
})

fastify.get('/b', async () => fastify.db)       // ❌ undefined

要让装饰器全局可见,用 fastify-plugin 包一层:

const fp = require('fastify-plugin')
fastify.register(fp(async (instance) => {
  instance.decorate('db', db)          // 现在全局可见
}))

常见坑

① 响应 schema 会吞字段

schema: { response: { 200: { properties: { id: {type:'integer'} } } } }
// handler 返回 { id: 1, secret: 'xxx' } → 响应里只有 id

看起来是 bug,其实是特性。调试时先怀疑 schema。

② 钩子的执行顺序

onRequest → preParsing → preValidation → preHandler → handler → preSerialization → onSend → onResponse。

鉴权放 onRequest 或 preHandler;想拿到解析后的 body 要放 preValidation 之后。

③ 异步钩子必须 await

fastify.addHook('preHandler', async (req, reply) => {
  await checkAuth(req)      // 不 await 的话鉴权会失效,但请求照常继续
})

什么时候选它

  • API 服务,有明确的数据契约
  • 对吞吐量有要求(比 Express 快 2-3 倍)
  • 需要自动生成 OpenAPI 文档
  • 愿意为性能多写 schema

不选它的场景:快速原型(写 schema 有成本)、需要海量 Express 中间件、团队不接受声明式风格。

一个性价比判断

写 schema 的成本,值不值?

  • 如果你的接口是给前端/第三方用的,值:schema 同时解决了校验、文档、序列化三个问题
  • 如果是内部临时接口,不值:直接用 Express 更快

Fastify 的性能优势在「响应体大、QPS 高」的场景才明显。小接口上,JSON.stringify 和编译序列化的差距用户感知不到。

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇