我尝试将nestjs后端和redis实现为缓存。我可以按照官方文件做https://docs.nestjs.com/techniques/caching#in-内存缓存。
我使用包cache-manager-redis-store
,app.module.ts
中的代码如下所示。
import { Module, CacheModule } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import * as redisStore from 'cache-manager-redis-store';
import * as Joi from 'joi';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
CacheModule.registerAsync({
imports: [
ConfigModule.forRoot({
validationSchema: Joi.object({
REDIS_HOST: Joi.string().default('localhost'),
REDIS_PORT: Joi.number().default(6379),
REDIS_PASSWORD: Joi.string(),
}),
}),
],
useFactory: async (configService: ConfigService) => ({
store: redisStore,
auth_pass: configService.get('REDIS_PASSWORD'),
host: configService.get('REDIS_HOST'),
port: configService.get('REDIS_PORT'),
ttl: 0,
}),
inject: [ConfigService],
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
有了这个设置,我可以按预期使用get
和set
,但我想使用其他redis命令,如hget
和zadd
。不幸的是,我在任何地方都找不到导游。
我认为一定有办法,因为cache-manager-redis-store
包说它只是将配置传递给底层的node_redis
包。而node-redis
包可以使用那些花哨的redis命令。
如果您有解决方案,我们将不胜感激。
感谢Micael Levi和Hamidreza Vakilian的帮助。我做了更多的研究,找到了我的解决方案,所以我会分享给其他有同样问题的人。
cache-manager-redis-store
似乎只允许正常的redis操作,如果你想使用更多,你必须按照Micael的建议访问cacheManager.store.getClient()
。
Cache
接口没有getClient
,但RedisCache
有!问题是cache-manager-redis-store
包中的RedisCache
接口没有为外部用户导出这些接口。
解决此问题的最简单方法是为自己创建redis.interface.ts
或任何名称。
import { Cache, Store } from 'cache-manager';
import { RedisClient } from 'redis';
export interface RedisCache extends Cache {
store: RedisStore;
}
export interface RedisStore extends Store {
name: 'redis';
getClient: () => RedisClient;
isCacheableValue: (value: any) => boolean;
}
现在您可以将Cache
替换为RedisCache
接口。
用法如下。
import {
CACHE_MANAGER,
Inject,
Injectable,
} from '@nestjs/common';
import { RedisClient } from 'redis';
import { RedisCache } from './interface/redis.interface';
@Injectable()
export class RedisService {
private redisClient: RedisClient;
constructor(@Inject(CACHE_MANAGER) private cacheManager: RedisCache) {
this.redisClient = this.cacheManager.store.getClient();
}
hgetall() {
this.redisClient.hgetall('mykey', (err, reply) => {
console.log(reply);
})
}
}
请注意,这些redisClient
命令不返回值,因此必须使用回调来获取值。
正如你所看到的,答案是回调结构,我更喜欢await
和async
,所以我做了更多的工作。
import {
BadRequestException,
CACHE_MANAGER,
Inject,
Injectable,
} from '@nestjs/common';
import { RedisClient } from 'redis';
import { RedisCache } from './interface/redis.interface';
@Injectable()
export class RedisService {
private redisClient: RedisClient;
constructor(@Inject(CACHE_MANAGER) private cacheManager: RedisCache) {
this.redisClient = this.cacheManager.store.getClient();
}
async hgetall(key: string): Promise<{ [key: string]: string }> {
return new Promise<{ [key: string]: string }>((resolve, reject) => {
this.redisClient.hgetall(key, (err, reply) => {
if (err) {
console.error(err);
throw new BadRequestException();
}
resolve(reply);
});
});
}
}
通过使用promise,我可以得到答案,就好像函数返回一样。用法如下。
import { Injectable } from '@nestjs/common';
import { RedisService } from './redis.service';
@Injectable()
export class UserService {
constructor(private readonly redisService: RedisService) {}
async getUserInfo(): Promise<{ [key: string]: string }> {
const userInfo = await this.redisService.hgetall('mykey');
return userInfo;
}
}
即使接口Cache
(来自cache-manager
)没有定义getClient
方法,也可以通过调用cacheManager.store.getClient()
来检索底层redis客户端。我不知道什么是最好的打字方式。
返回的将是cache-manager-redis-store
创建的Redis客户端
我建议使用nestjs-redis包。它与typescript兼容,并且依赖于ioredis包,因此您也可以获得所有其他Redis API。
我找到了另一种简单的方法!您可以从cache-manager-redis-yet
导入RedisCache
,这是一个官方包,由节点缓存管理器建议。
这是代码示例:
import { CACHE_MANAGER, Injectable, Inject } from '@nestjs/common';
import { RedisCache } from 'cache-manager-redis-yet';
@Injectable()
export class UserService {
constructor(@Inject(CACHE_MANAGER) private readonly cacheManager: RedisCache) {}
get redis() {
return this.cacheManager.store.client;
}
async getUserInfo(): Promise<{ [key: string]: string }> {
const userInfo = await this.redis.hGetAll('mykey');
return userInfo;
}
}