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
相关产品推荐
相关产品推荐

