我想在nestjs中实现自定义缓存

时间:2019-02-03 23:13:05

标签: typescript nestjs

nsetjs中的默认缓存机制没有提供足够的灵活性,因为您无法使用@Cache指令或类似的注释来对单个routes/methods进行注释。

我希望能够设置自定义ttl,也不想缓存每条路由。为此,尚不确定将缓存移到服务级别是否有意义,

只是想知道如何使用nestjs框架以更好的方式做到这一点。只是为了缓存特定的路由或服务方法。

1 个答案:

答案 0 :(得分:0)

在遇到与您同样的问题后,我最近开始为NestJS进行缓存模块的开发。尽管尚未准备好使用它,但它可以在npm的@nestjs-plus/caching上使用,但我将在此处共享Interceptor的定义。它依靠mixin模式来接收每个路由选项。

import { makeInjectableMixin } from '@nestjs-plus/common';
import {
  ExecutionContext,
  Inject,
  Injectable,
  NestInterceptor
} from '@nestjs/common';
import { forkJoin, Observable, of } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';
import { Cache, CacheToken } from './cache';

@Injectable()
export abstract class CachingInterceptor implements NestInterceptor {
  protected abstract readonly options: CacheOptions;

  constructor(@Inject(CacheToken) private readonly cache: Cache) {}

  async intercept(
    context: ExecutionContext,
    call$: Observable<any>
  ): Promise<Observable<any>> {
    const http = context.switchToHttp();
    const request = http.getRequest();
    const key = this.options.getKey(request);

    const cached = await this.cache.get(key);
    if (cached != null) {
      return of(cached);
    }

    return call$.pipe(
      switchMap(result => {
        return forkJoin(
          of(result),
          this.cache.set(key, result, this.options.ttl)
        ).pipe(catchError(e => of(result)));
      }),
      map(([result, setOp]) => result)
    );
  }
}

export interface CacheOptions {
  ttl: number;
  getKey: (request) => string;
}

export const makeCacheInterceptor = (options: CacheOptions) => {
  return makeInjectableMixin('CachingInterceptor')(
    class extends CachingInterceptor {
      protected readonly options = options;
    }
  );
};

export interface Cache {
  get: (key: string) => Promise<any | null | undefined>;
  set: (key: string, data: any, ttl: number) => Promise<void>;
  del: (key: string) => Promise<void>;
}

export const CacheToken = Symbol('CacheToken');

此模式允许在具有不同TTL的控制器中应用每个路由的缓存,或者从传入请求中提取缓存密钥的方法。

@Get()
  @UseInterceptors(
    makeCacheInterceptor({
      getKey: () => '42' // could be req url, query params, etc,
      ttl: 5,
    }),
  )
  getHello(): string {
    return this.appService.getHello();
  }

这里(以及我正在使用的库)唯一缺少的是一组灵活的缓存实现,例如内存,redis,db等。我计划与缓存管理器库集成以填补这一空白本周(与Nest用于默认缓存实现的缓存提供商相同)。随时可以将其用作创建自己的基础,或者随时准备使用@nestjs-plus/caching。我将在本周晚些时候发布正式版时更新此问题。