Skip to content

在 NestJS 项目中集成 redis

安装依赖

shell
pnpm install @nestjs/cache-manager cache-manager cache-manager-redis-yet redis --save

在 linux 服务器上安装 redis 并开启防火墙和安全组

redis数据库密码:MyRedis@123

异步注册 reds

ts
import { Module, CacheModule } from '@nestjs/common';
import * as redisStore from 'cache-manager-redis-yet';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    // 先注册配置模块,读取 .env 文件
    ConfigModule.forRoot({ isGlobal: true }),
    // 异步注册缓存模块
    CacheModule.registerAsync({
      isGlobal: true,
      useFactory: (configService: ConfigService) => ({
        store: redisStore,
        host: configService.get('REDIS_HOST', 'localhost'),
        port: configService.get('REDIS_PORT', 6379),
        password: configService.get('REDIS_PASSWORD', ''),
        db: configService.get('REDIS_DB', 0),
        ttl: configService.get('REDIS_TTL', 3600),
      }),
      inject: [ConfigService], // 注入配置服务
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

在 .env 环境变量中配置

shell
# Redis 数据库配置
REDIS_HOST=47.92.68.193
REDIS_PORT=6379
REDIS_PASSWORD=MyRedis@123
REDIS_DB=0
REDIS_TTL=864000

使用(方式一:依赖注入)

ts
import { Inject, Injectable } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';

@Injectable()
export class TokenService {
  // 注入CacheManager实例
  constructor(@Inject(CACHE_MANAGER) private readonly cacheManager: Cache) {}

  /**
   * 存储过期/失效的Token到Redis,并设置单独过期时间
   * @param token 失效的Token字符串
   * @param ttl 单独过期时间(秒),优先级高于全局TTL
   * @returns 
   */
  async storeExpiredToken(token: string, ttl: number): Promise<void> {
    // 核心方法:cacheManager.set(key, value, ttl)
    // 这里key为token本身,value可设为标记(如'expired'),ttl为过期时间(秒)
    await this.cacheManager.set(
      token, // 缓存key(Token唯一标识)
      'expired', // 缓存value(标记Token状态)
      ttl, // 单独设置过期时间(秒),可选:若不传则使用全局TTL
    );
  }

  /**
   * 验证Token是否已过期(是否存在于Redis缓存中)
   * @param token 待验证的Token字符串
   * @returns boolean(true:已过期,false:有效/未缓存)
   */
  async isTokenExpired(token: string): Promise<boolean> {
    // 核心方法:cacheManager.get(key)
    const cachedToken = await this.cacheManager.get(token);
    // 若缓存存在,说明Token已失效;否则有效
    return !!cachedToken;
  }

  /**
   * 手动删除Redis中的过期Token(可选)
   * @param token 待删除的Token字符串
   * @returns 
   */
  async removeExpiredToken(token: string): Promise<void> {
    await this.cacheManager.del(token);
  }
}

使用(方式二:装饰器)

ts
import { Controller, Get, Param, CacheKey, CacheTTL } from '@nestjs/common';
import { AppService } from './app.service';

@Controller('demo')
export class AppController {
  constructor(private readonly appService: AppService) {}

  // 为该接口添加缓存,默认使用接口路径作为缓存键
  @Get('user/:id')
  @CacheTTL(7200) // 单独指定该接口缓存过期时间(秒),覆盖全局配置
  async getUserInfo(@Param('id') id: string) {
    // 模拟数据库查询(实际业务中替换为真实数据查询)
    return {
      userId: id,
      username: `user_${id}`,
      age: Math.floor(Math.random() * 30) + 20,
    };
  }

  // 自定义缓存键名
  @Get('article/:id')
  @CacheKey('article_') // 缓存键前缀,最终键为 article_{id}
  @CacheTTL(86400)
  async getArticleInfo(@Param('id') id: string) {
    return {
      articleId: id,
      title: `文章_${id}`,
      content: '这是一篇测试文章内容',
      createTime: new Date().toISOString(),
    };
  }
}