You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fastify认证装饰器作为preHandler时出现undefined错误求助

Fastify认证装饰器preHandler报错:FST_ERR_HOOK_INVALID_HANDLER的排查方案

问题场景

使用Fastify v5构建API时,在路由中使用fastify.authenticate作为preHandler钩子时抛出错误:

{"code":"FST_ERR_HOOK_INVALID_HANDLER","name":"FastifyError","statusCode":500,"msg":"preHandler hook should be a function, instead got [object Undefined]"}

已完成的操作:

  • 在@/decorators/authentication.ts中定义认证装饰器,注册@fastify/jwt和@fastify/cookie插件,并通过app.decorate('authenticate', ...)添加认证方法
  • 在@/modules/authentication/authentication.routes.ts的/me路由中,尝试将fastify.authenticate作为preHandler使用,但该值为undefined
  • 确认server.ts中先注册认证装饰器,再注册路由,顺序正确
  • 使用包版本:@fastify/cookie@^10.0.1、@fastify/jwt@^9.0.1、fastify@^5.0.0、fastify-zod@^1.4.0

可能的原因及解决方法

1. 装饰器未按Fastify插件规范实现

检查@/decorators/authentication.ts,必须确保:

  • 装饰器是标准的Fastify插件函数(接收fastify实例和options参数,返回Promise或调用done)
  • fastify.decorate('authenticate', ...)传入的是有效的钩子函数(格式为async (request, reply) => {})

示例正确实现:

// @/decorators/authentication.ts
import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';

export default async function authenticationDecorator(fastify: FastifyInstance) {
  // 注册依赖插件
  await fastify.register(require('@fastify/cookie'));
  await fastify.register(require('@fastify/jwt'), {
    secret: process.env.JWT_SECRET!,
    cookie: { cookieName: 'token', signed: false }
  });

  // 装饰认证方法
  fastify.decorate('authenticate', async function authenticate(request: FastifyRequest, reply: FastifyReply) {
    try {
      await request.jwtVerify();
    } catch (err) {
      reply.send(err);
    }
  });
}

2. 路由文件未获取已装饰的Fastify实例

如果路由是通过fastify.register加载的插件,必须在路由函数中通过参数获取fastify实例,而非直接导入全局未完成装饰的实例:

// @/modules/authentication/authentication.routes.ts
import type { FastifyInstance } from 'fastify';

export default async function authenticationRoutes(fastify: FastifyInstance) {
  fastify.get('/me', {
    preHandler: fastify.authenticate // 此处的fastify是已完成装饰的实例
  }, async (request, reply) => {
    return request.user;
  });
}

3. Fastify v5的异步注册顺序问题

Fastify v5严格要求异步操作完成后再执行后续注册,确保server.ts中装饰器注册使用await,避免路由在装饰器未完成时加载:

// server.ts
import fastify from 'fastify';
import authenticationDecorator from '@/decorators/authentication';
import authenticationRoutes from '@/modules/authentication/authentication.routes';

const app = fastify();

// 先等待装饰器注册完成
await app.register(authenticationDecorator);
// 再注册路由
await app.register(authenticationRoutes);

await app.listen({ port: 3000 });

4. 模块导入路径错误

检查server.ts中装饰器的导入路径是否正确,避免因路径解析错误导致装饰器未被实际注册(比如别名配置错误、相对路径写错)。

5. TypeScript类型定义缺失(可选)

若使用TypeScript,需扩展Fastify类型定义,确保fastify.authenticate被类型系统识别,避免隐性错误:

// @/types/fastify.d.ts
import type { FastifyRequest, FastifyReply } from 'fastify';

declare module 'fastify' {
  interface FastifyInstance {
    authenticate: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
  }
}

内容的提问来源于stack exchange,提问作者Nicolas Bispo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 10:05:10