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

Redis报错:The client is closed,登录后缓存Token失败求助

问题排查:Redis客户端关闭错误(Error: The client is closed)

问题背景

在NestJS应用中实现用户登录后将JWT Token存入Redis缓存,但调用登录接口时控制台报错Error: The client is closed,执行DEBUG=* npm run start:dev启动应用也未看到Redis相关日志。相关代码如下:

缓存配置服务(cache.config.service.ts)

@Injectable()
export class CacheConfigService {
  constructor(private configService: ConfigService) {}

  get url(): string {
    console.log(this.configService.get<string>('redis.url'));
    return this.configService.get<string>('redis.url') as string;
  }
}

缓存模块(cacheModule.ts)

@Module({
  imports: [
    CacheModule.register<RedisClientOptions>({
      // @ts-ignore
      store: createRedisStore,
      socket: {
        host: 'localhost',
        port: 6379,
      },
      isGlobal: true,
      // url: 'redis://' + process.env.REDIS_HOST + ':' + process.env.REDIS_PORT,
    }),
  ],
})

用户登录方法

emailPasswordSignInPOST: async (input: any) => {
  if (
    originalImplementation.emailPasswordSignInPOST === undefined
  ) {
    throw Error('Should never come here');
  }
  let response: any =
    await originalImplementation.emailPasswordSignInPOST(input);

  const formFields: any = input.formFields;
  const inputObject: any = {};

  for (let index = 0; index < formFields.length; index++) {
    const element = formFields[index];
    inputObject[element.id] = element.value;
  }
  const { email } = inputObject;
  const user = await this.userService.findOneByEmail(email);
  const id = user?.id;

  const payload = { email, id };
  const secret = 'mysecret';
  const token = jwt.sign(payload, secret, {
    expiresIn: '2h',
  });
  response.token = token;
  const cacheKey = 'Token';
  await this.redisClient.set(cacheKey, token, {
    EX: 60 * 60 * 24,
  });
  return response;
},

排查步骤与解决方案

1. 修正Redis客户端注入方式

The client is closed报错核心原因是代码中使用的redisClient未通过NestJS依赖注入正确获取实例,或未完成连接:

  • 改用NestJS官方推荐的CACHE_MANAGER注入:
    import { CACHE_MANAGER, Inject } from '@nestjs/common';
    import { Cache } from 'cache-manager';
    
    // 在类构造函数中注入缓存管理器
    constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
    
    // 存储Token时替换原有redisClient调用
    await this.cacheManager.set(cacheKey, token, 60 * 60 * 24); // 第三个参数为过期时间(秒)
    

2. 修复CacheModule配置兼容性问题

当前配置的Redis Store存在类型与版本适配问题:

  • 移除@ts-ignore,使用官方适配的Redis存储包(如cache-manager-redis-yet),调整配置为异步注册模式:
    import { CacheModule } from '@nestjs/cache-manager';
    import { redisStore } from 'cache-manager-redis-yet';
    import type { RedisClientOptions } from 'redis';
    
    @Module({
      imports: [
        CacheModule.registerAsync<RedisClientOptions>({
          isGlobal: true,
          useFactory: async () => ({
            store: await redisStore({
              socket: {
                host: 'localhost',
                port: 6379,
              },
            }),
          }),
        }),
      ],
    })
    
  • 配置中添加日志输出,便于排查连接问题:
    store: await redisStore({
      socket: {
        host: 'localhost',
        port: 6379,
      },
      logger: 'debug',
    })
    

3. 验证Redis服务可用性

  • 执行redis-cli ping命令,返回PONG则表示Redis服务正常运行,否则启动本地Redis服务;
  • 检查6379端口是否被占用,确保应用能正常访问localhost:6379。

4. 调试连接过程

在CacheModule的useFactory中添加错误捕获,直接输出连接失败原因:

useFactory: async () => {
  try {
    const store = await redisStore({
      socket: {
        host: 'localhost',
        port: 6379,
      },
    });
    console.log('Redis连接成功');
    return { store };
  } catch (err) {
    console.error('Redis连接失败详情:', err);
    throw err;
  }
},

内容的提问来源于stack exchange,提问作者John Oliver

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 18:40:16