Nest 操作 Redis

990 阅读3分钟

Node 中操作 Redis 简介

在 Node.js 中,我们通常使用 Redis 客户端库来与 Redis 数据库交互。以下是两种流行的 Redis Node 客户端:

  1. redis:由官方提供的 npm 包。
  2. ioredis:一个功能丰富的第三方 Redis 客户端。

image.png
redis 还有很多的 node 客户端的包

使用 redis 包操作 Redis

创建项目:

mkdir redis-node-test
cd redis-node-test
npm init -y
npm install redis

使用 ES Module 和顶层 await,需要在 package.json 中添加 "type": "module":
image.png
创建 index.js 连接 redis 服务:

import { createClient } from 'redis'

// 创建客户端实例
const client = createClient({
	socket: {
		host: 'localhost',
		port: 6379,
	},
})

// 监听错误事件
client.on('error', err => console.log('Redis Client Error', err))

// 连接 Redis 服务
await client.connect()

// 执行 keys 命令,获取所有键
const value = await client.keys('*')

console.log(value)

// 断开连接
await client.disconnect()

node 执行:
image.png
用 RedisInsight 看下 key:
image.png
没问题。
所有的 redis 命令都有对应的方法:
image.png
和我们在命令行客户端里操作一样。

使用 ioredis 包操作 Redis

安装 ioredis:

npm install ioredis

连接 redis 执行命令:

import Redis from 'ioredis'

const redis = new Redis()

const res = await redis.keys('*')

console.log(res)

image.png
image.png

在 Nest 中操作 Redis

创建 nest 项目:

nest new nest-redis -p npm

安装 redis 的包:

npm install redis

在 AppModule 添加一个自定义的 provider:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { createClient } from 'redis';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: 'REDIS_CLIENT', // 定义一个提供者的键
      async useFactory() { // 使用工厂模式创建 Redis 客户端
        const client = createClient({
          socket: {
            host: 'localhost', // Redis 服务器主机名
            port: 6379, // Redis 服务器端口
          },
        });
        await client.connect(); // 连接到 Redis 服务器
        return client; // 返回连接后的 Redis 客户端
      },
    },
  ],
})
export class AppModule {}

注入就可以使用了:

import { Inject, Injectable } from '@nestjs/common';
import { RedisClientType } from 'redis';

@Injectable()
export class AppService {
  @Inject('REDIS_CLIENT')
  private redisClient: RedisClientType;

  async getHello() {
    const value = await this.redisClient.keys('*');
    console.log(value);

    return 'Hello World!';
  }
}

Controller 中也需要相应地使用 async/await:
image.png
运行项目,浏览器访问下:

nest start:dev

image.png
这样就能在 nest 里操作 redis 了。

Nest 与 redis 缓存

Nest 的官方文档中推荐使用 cache-manager,但是它仅支持基础的 get 和 set 操作和基本缓存,不支持 list、hash、zset 等数据结构。
我们如上面一样封装 RedisService ,来实现 get、set 和其他操作更灵活。
至于缓存,我们也可以自己封装个拦截器。
创建一个 interceptor:

nest g interceptor my-cache --no-spec --flat

内容如下:

import {
	CallHandler,
	ExecutionContext,
	Inject,
	Injectable,
	NestInterceptor,
} from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
import { RedisClientType } from 'redis';
import { of, tap } from 'rxjs';

@Injectable()
export class MyCacheInterceptor implements NestInterceptor {
	// 注入Redis客户端
	@Inject('REDIS_CLIENT')
	private redisClient: RedisClientType;

	// 注入HttpAdapterHost,用于访问HTTP请求信息
	@Inject(HttpAdapterHost)
	private httpAdapterHost: HttpAdapterHost;

	async intercept(context: ExecutionContext, next: CallHandler) {
		const request = context.switchToHttp().getRequest();

		// 生成缓存键,基于请求的URL
		const key = this.httpAdapterHost.httpAdapter.getRequestUrl(request);

		// 尝试从Redis获取缓存数据
		const value = await this.redisClient.get(key);

		// 如果缓存不存在,则处理请求并把结果缓存
		if (!value) {
			return next.handle().pipe(
				tap(res => {
					// 请求处理完成后,将结果缓存到Redis
					this.redisClient.set(key, res);
				})
			);
		} else {
			// 如果缓存存在,直接返回缓存数据
			return of(value);
		}
	}
}

总结

通过 redis 和 ioredis 等 npm 包,我们可以连接到 Redis 服务器并执行各种命令。
在 Nest.js 中,可以通过 useFactory 动态创建一个 Provider 来管理 Redis 客户端连接。
如果需要缓存接口,可以自己创建拦截器。