缓存
缓存 是一种出色且简单的技术,有助于提高应用程序的性能。它充当临时数据存储,提供高性能的数据访问。
安装
首先安装所需的包:
npm install @nestjs/cache-manager cache-manager
cache-manager
版本 4 使用秒作为 TTL(Time-To-Live)。当前版本的 cache-manager
(v5)已切换为使用毫秒。
NestJS 不会转换该值,只会将您提供的 TTL 直接传递给库。换句话说:
- 如果使用
cache-manager
v4,请以秒为单位提供 TTL。 - 如果使用
cache-manager
v5,请以毫秒为单位提供 TTL。 - 文档引用的是秒,因为 NestJS 发布时针对
cache-manager
版本 4。
内存缓存
Nest 提供了各种缓存存储提供程序的统一 API。内置的缓存存储是一个内存数据存储。 但是,您可以轻松切换到更全面的解决方案,比如 Redis。
为了启用缓存,请导入 CacheModule
并调用其 register()
方法。
import { Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
import { AppController } from './app.controller';
@Module({
imports: [CacheModule.register()],
controllers: [AppController],
})
export class AppModule {}
与缓存存储交互
要与缓存管理器实例交互,请使用 CACHE_MANAGER
令牌将其注入到您的类中,如下所示:
constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
Cache
类是从 cache-manager
导入的,而 CACHE_MANAGER
令牌来自 @nestjs/cache-manager
包。
使用 Cache
实例(来自 cache-manager
包)上的 get
方法从缓存中检索项目。
如果缓存中不存在该项,则将返回 null
。
const value = await this.cacheManager.get('key');
要将项目添加到缓存,请使用 set
方法:
await this.cacheManager.set('key', 'value');
缓存的默认过期时间是 5 秒。
您可以为此特定键手动指定 TTL(以秒为单位的过期时间),如下所示:
await this.cacheManager.set('key', 'value', 1000);
要禁用缓存的过期时间,请将 ttl
配置属性设置为 0:
await this.cacheManager.set('key', 'value', 0);
要从缓存中删除项目,请使用 del
方法:
await this.cacheManager.del('key');
要清除整个缓存,请使用 reset
方法:
await this.cacheManager.reset();
自动缓存响应
在 GraphQL 应用程序中,拦截器分别对每个字段解析器执行。
因此,使用拦截器缓存响应的 CacheModule
将无法正常工作。
要启用自动缓存响应,只需在要缓存数据的位置使用 CacheInterceptor
。
@Controller()
@UseInterceptors(CacheInterceptor)
export class AppController {
@Get()
findAll(): string[] {
return [];
}
}
只有 GET 端点会被缓存。此外,使用本机响应对象(@Res()
)注入的 HTTP 服务器路由无法使用缓存拦截器。
有关更多详细信息,请参阅响应映射。
为了减少所需的样板代码,您可以将 CacheInterceptor
绑定到所有端点:
import { Module } from '@nestjs/common';
import { CacheModule, CacheInterceptor } from '@nestjs/cache-manager';
import { AppController } from './app.controller';
import { APP_INTERCEPTOR } from '@nestjs/core';
@Module({
imports: [CacheModule.register()],
controllers: [AppController],
providers: [
{
provide: APP_INTERCEPTOR,
useClass: CacheInterceptor,
},
],
})
export class AppModule {}
自定义缓存
所有缓存的数据都有自己的过期时间([TTL](https://en.wikipedia.org/wiki/Time_to_live))。
要自定义默认值,请将选项对象传递给 register()
方法。
CacheModule.register({
ttl: 5, // 秒
max: 10, // 缓存中的最大项目数
});
全局使用模块
当您想在其他模块中使用 CacheModule
时,您需要导入它(与任何 Nest 模块一样)。
或者,通过将选项对象的 isGlobal
属性设置为 true
,将其声明为全局模块,
如下所示。
在这种情况下,一旦在根模块(例如,AppModule
)中加载了 CacheModule
,您将无需在其他模块中导入它。
CacheModule.register({
isGlobal: true,
});
全局缓存覆盖
启用全局缓存时,缓存条目存储在基于路由路径自动生成的 CacheKey
下。
您可以在每个方法基础上覆盖特定的缓存设置(@CacheKey()
和 @CacheTTL()
),
允许为各个控制器方法自定义缓存策略。
在使用不同的缓存存储时,这可能最相关。
@Controller()
export class AppController {
@CacheKey('custom_key')
@CacheTTL(20)
findAll(): string[] {
return [];
}
}
@CacheKey()
和 @CacheTTL()
装饰器是从 @nestjs/cache-manager
包导入的。
@CacheKey()
装饰器可以与相应的 @CacheTTL()
装饰器一起使用,也可以反之。
您可以选择只覆盖 @CacheKey()
或仅覆盖 @CacheTTL()
。
未使用装饰器覆盖的设置将使用全局注册时的默认值(请参阅自定义缓存)。
WebSockets 和微服务
您还可以将 CacheInterceptor
应用于 WebSocket 订阅者以及微服务的模式(无论使用的是哪 种传输方法)。
@CacheKey('events')
@UseInterceptors(CacheInterceptor)
@SubscribeMessage('events')
handleEvent(client: Client, data: string[]): Observable<string[]> {
return [];
}
然而,为了指定用于随后存储和检索缓存数据的键,需要额外的 @CacheKey()
装饰器。
此外,请注意,不应缓存所有内容。
执行一些业务操作而不仅仅是查询数据的操作不应该被缓存。
此外,您还可以使用 @CacheTTL()
装饰器指定缓存的过期时间(TTL),该装饰器将覆盖全局默认的 TTL 值。
@CacheTTL(10)
@UseInterceptors(CacheInterceptor)
@SubscribeMessage('events')
handleEvent(client: Client, data: string[]): Observable<string[]> {
return [];
}
@CacheTTL()
装饰器可以与或不使用相应的 @CacheKey()
装饰器一起使用。