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

Fastify调用jwt.sign报undefined读取sign属性错误排查

Fastify JWT 生成器 sign 方法未定义报错修复方案

问题描述

基于Fastify规范开发后端JWT生成器时,运行抛出如下错误:

Cannot read properties of undefined (reading 'sign')

错误根因

报错由两个核心问题导致:

  • Fastify实例重复初始化,上下文不互通:你在JWT工具函数文件中单独执行const fastify = require('fastify')()创建了一个全新的Fastify实例,这个实例从未注册过@fastify/jwt插件,本身不存在jwt属性,调用.sign方法时自然会读到undefined。而你在main.ts中注册JWT插件用的是名为app的另一个独立Fastify实例,两个实例的插件、装饰器完全不共享。
  • 插件注册存在时序隐患:Fastify的registerAPI是异步执行的,你当前写法没有等待插件加载完成就注册路由、启动服务,即使实例统一,也可能出现插件未初始化完成就调用JWT方法的问题。

修复方案

1. 删除重复初始化的Fastify实例,统一上下文

删掉工具文件中单独创建Fastify实例的代码,将注册了所有插件的主Fastify实例作为参数传入JWT生成函数:

// 移除这行重复初始化的错误代码
// const fastify = require('fastify')()

import type { FastifyInstance } from 'fastify'
import { randomBytes, createHash } from "crypto";
import { users } from ".prisma/client";
// 未使用的导入(比如单独导入的jsonwebtoken类型、node-fetch等)可以一并清理

// 新增Fastify实例作为入参
function generateJWTToken(fastify: FastifyInstance, user: users) {
  const { password, sal, active, ...enviar } = user;

  const token = fastify.jwt.sign({
    ...enviar,
    // 可主动配置过期时间,例如 { expiresIn: '2h' }
  });

  const decoded = fastify.jwt.decode<{ exp: number }>(token, { complete: true });

  return {
    token,
    uuid: user.id,
    nombre: `${user.name} ${user.lastname_p} ${user.lastname_m}`,
    exp: decoded.payload.exp,
  };
}

在路由处理逻辑中调用该函数时,直接传入当前请求上下文绑定的Fastify实例即可:

// 路由注册示例
authRouterWeb.post('/login', async (request, reply) => {
  // 省略用户账号密码校验逻辑
  const user = await fastify.prisma.users.findUnique(/* 你的查询条件 */)
  // 传入fastify实例调用生成函数
  const authData = generateJWTToken(fastify, user)
  return reply.send(authData)
})

2. 等待插件注册完成再启动服务

修改main.ts中的启动逻辑,所有register调用前加await,确保所有插件、路由加载完成后再启动端口监听,避免时序问题:

async function main() {
  await app.register(require("@fastify/swagger"), swaggerOptions);
  
  await app.register(require('@fastify/jwt'), {
    secret: process.env.JWT_SECRET || 'supersecret' // 建议优先读取环境变量
  })

  app.decorate("prisma", prisma);

  await app.register(require("@fastify/cors"), {
    origin: "*",
    methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allowedHeaders: ["Content-Type", "Authorization", "Accept"],
  });

  await app.register(authRouterWeb, {
    prefix: "/api/v1/auth-web",
  });

  app.listen(port, (err, address) => {
    if (err) {
      app.log.error(err);
      process.exit(1);
    }
    app.log.info(`server listening on ${address}`);
  });
}

额外优化建议

  • 移除冗余依赖:@fastify/jwt内部已经封装了jsonwebtoken的全部能力,且自带完整TS类型支持,不需要额外安装jsonwebtoken包、导入相关类型,减少依赖冗余。
  • 敏感配置不要硬编码:JWT密钥、服务端口、数据库连接串这类配置统一从环境变量读取,避免敏感信息随代码仓库泄露。
  • 统一实例管理:不要在单独的工具文件顶层初始化Fastify、Prisma这类全局服务实例,统一通过Fastify装饰器挂载、参数传递的方式共享实例,从根源上避免多实例不一致的问题。
  • 签发JWT时主动配置有效期、签发者等属性,不要依赖默认配置,方便后续做token过期、续签策略调整。

内容的提问来源于stack exchange,提问作者Ernesto Vazquez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 22:27:33