zvvq技术分享网

Node.js中怎么使用Redis?原来这么简单!(node re

作者:zvvq博客网
导读node 中怎么使用redis?下面本篇文章给大家介绍一下node.js中使用redis的方法,你会发现原来这么简单,希望对大家有所帮助! 之前的文章中我们其实留了两个可以用redis优化的地方: 一

node中怎么使用redis?下面本篇文章给大家介绍一下node.js中使用redis的方法,你会发现原来这么简单,希望对大家有所帮助!

zvvq.cn

本文来自zvvq

之前的文章中我们其实留了两个可以用redis优化的地方: zvvq

一个是我们的在做登录时,通过JWT已经实现了服务端生成token以及验证客户端发送的token信息。【相关教程推荐:nodejs视频教程 、编程视频】 实现对文章点赞功能,采用的是将点赞数据直接写入数据库

JWT token 实现方式, 将基本信息直接放在token中,以便于分布式系统使用, 但是我们没有设置有限期(这个是可以实现的),并且服务端无法主动让token失效。 而Redis天然支持过期时间,也能实现让服务端主动使token过期。 内容来自zvvq

当然并不是说JWT token 不如 redis+token实现方案好, 具体看使用的场景,这里我们并不讨论二者孰优孰劣,只是提供一种实现方案,让大家知道如何实现。 本文来自zvvq

1. 认识redis

对于前端的小伙伴来说,Redis可能相对比较陌生,首先认识一下 zvvq.cn

Redis是什么

Redis是一个开源(BSD许可)的,基于内存的数据结构存储系统,它可以用作数据库、缓存和消息中间件,是现在最受欢迎的 NoSQL 数据库之一。 zvvq好,好zvvq

其具备如下特性: 内容来自zvvq

速度快 单节点读110000次/s,写81000次/s 基于内存运行,性能高效 用 C 语言实现,离操作系统更近 持久化数据的更新将异步地保存到硬盘(RDB 和 AOF 多种数据结构 不仅仅支持简单的 key-value 类型数据 还支持:字符串、hash、列表、集合、有序集合 支持多种编程语言等等

Redis 典型使用场景

缓存

zvvq好,好zvvq

缓存可以说是Redis最常用的功能之一了, 合理的缓存不仅可以加快访问的速度,也可以减少后端数据库的压力。

copyright zvvq

排行系统 本文来自zvvq

利用Redis的列表和有序集合的特点,可以制作排行榜系统,而排行榜系统目前在商城类、新闻类、博客类等等,都是比不可缺的。

内容来自samhan

计数器应用 copyright zvvq

计数器的应用基本和排行榜系统一样,都是多数网站的普遍需求,如视频网站的播放计数,电商网站的浏览数等等,但这些数量一般比较庞大,如果存到关系型数据库,对MySQL或者其他关系型数据库的挑战还是很大的,而Redis基本可以说是天然支持计数器应用。 内容来自samhan666

(视频直播)消息弹幕

内容来自zvvq

直播间的在线用户列表,礼物排行榜,弹幕消息等信息,都适合使用Redis中的SortedSet结构进行存储。 内容来自zvvq

例如弹幕消息,可使用ZREVRANGEBYSCORE排序返回,在Redis5.0中,新增了zpopmax,zpopmin命令,更加方便消息处理。

zvvq好,好zvvq

Redis的应用场景远不止这些,Redis对传统磁盘数据库是一个重要的补充,是支持高并发访问的互联网应用必不可少的基础服务之一。 内容来自samhan666

纸上谈兵终觉浅,必须实战一波~ 内容来自samhan

Redis的安装和简单使用,我这里就不一一介绍了,这里贴上我之前写的两篇文章: zvvq

Redis 安装 Redis入门篇-基础使用

可以快速的安装、了解Redis数据类型以及常用的命令。 内容来自samhan666

可视化客户端

在Windows下使用 RedisClient, 在mac下可以使用Redis Desktop Manager zvvq.cn

RedisClient下载链接:https://github.com/caoxinyu/RedisClient 内容来自samhan

下载后直接双击redisclient-win32.x86.2.0.exe文件运行即可

zvvq

本文来自zvvq

启动后, 点击server -> add

copyright zvvq

内容来自zvvq

连接后就可以看到总体情况了: zvvq.cn

zvvq

与SQL型数据不同,redis没有提供新建数据库的操作,因为它自带了16(0-15)个数据库(默认使用0库)。在同一个库中,key是唯一存在的、不允许重复的,它就像一把“密钥”,只能打开一把“锁”。键值存储的本质就是使用key来标识value,当想要检索value时,必须使用与value对应的key进行查找. zvvq好,好zvvq

Redis认识作为文章前置条件,到这里及结束了, 接下来进入正题~ zvvq

本文主要使用Redis实现缓存功能。 本文来自zvvq

2. 在Nest.js中使用

版本情况: copyright zvvq

库 版本 Nest.js V8.1.2

项目是基于Nest.js 8.x版本,与Nest.js 9.x版本使用有所不同, 后面的文章专门整理了两个版本使用不同点的说明, 以及如何从V8升级到V9, 这里就不过多讨论。 内容来自samhan666

首先,我们在Nest.js项目中连接Redis, 连接Redis需要的参数: zvvq.cn

1 内容来自samhan

2

copyright zvvq

3 内容来自zvvq

4 内容来自samhan666

REDIS_HOST:Redis 域名

本文来自zvvq

REDIS_PORT:Redis 端口号 内容来自samhan666

REDIS_DB: Redis 数据库 zvvq.cn

REDIS_PASSPORT:Redis 设置的密码

内容来自zvvq,别采集哟

将参数写入.env与.env.prod配置文件中: 内容来自samhan666

内容来自zvvq

使用Nest官方推荐的方法,只需要简单的3个步骤: zvvq.cn

1、引入依赖文件

zvvq

1

copyright zvvq

2 zvvq

3 zvvq.cn

npm install cache-manager --save

本文来自zvvq

npm install cache-manager-redis-store --save copyright zvvq

npm install @types/cache-manager -D

zvvq.cn

Nest为各种缓存存储提供统一的API,内置的是内存中的数据存储,但是也可使用 cache-manager来使用其他方案, 比如使用Redis来缓存。

内容来自samhan666

为了启用缓存, 导入ConfigModule, 并调用register()或者registerAsync()传入响应的配置参数。

内容来自zvvq

2、创建module文件src/db/redis-cache.module.ts, 实现如下: 内容来自samhan

1

内容来自zvvq

2 内容来自zvvq,别采集哟

3

内容来自samhan666

4

zvvq.cn

5

内容来自samhan

6 内容来自samhan

7 本文来自zvvq

8 copyright zvvq

9 本文来自zvvq

10

zvvq.cn

11

内容来自zvvq,别采集哟

12 zvvq好,好zvvq

13

zvvq好,好zvvq

14 zvvq

15

copyright zvvq

16

zvvq.cn

17

copyright zvvq

18 copyright zvvq

19 zvvq.cn

20

内容来自zvvq

21 内容来自zvvq

22 copyright zvvq

23 zvvq.cn

24 zvvq.cn

25

本文来自zvvq

26 内容来自samhan666

import { ConfigModule, ConfigService } from &39;@nestjs/config&39;; zvvq

import { RedisCacheService } from &39;./redis-cache.service&39;;

zvvq好,好zvvq

import { CacheModule, Module, Global } from &39;@nestjs/common&39;; 内容来自zvvq,别采集哟

import as redisStore from &39;cache-manager-redis-store&39;;

内容来自samhan

@Module({

zvvq好,好zvvq

imports: [ zvvq

CacheModule.registerAsync({ zvvq

isGlobal: true,

本文来自zvvq

imports: [ConfigModule], zvvq.cn

inject: [ConfigService], 内容来自samhan

useFactory: async (configService: ConfigService) => {

zvvq

return {

内容来自zvvq

store: redisStore, zvvq好,好zvvq

host: configService.get(&39;REDIS_HOST&39;), 本文来自zvvq

port: configService.get(&39;REDIS_PORT&39;),

内容来自samhan666

db: 0, //目标库, 本文来自zvvq

auth_pass:  configService.get(&39;REDIS_PASSPORT&39;) // 密码,没有可以不写 内容来自zvvq

}; 内容来自zvvq,别采集哟

},

内容来自samhan

}), 本文来自zvvq

], 内容来自zvvq

providers: [RedisCacheService],

内容来自zvvq,别采集哟

exports: [RedisCacheService],

zvvq

}) copyright zvvq

export class RedisCacheModule {}

zvvq.cn

CacheModule的registerAsync方法采用 Redis Store 配置进行通信store 属性值redisStore ,表示cache-manager-redis-store 库isGlobal 属性设置为true 来将其声明为全局模块,当我们将RedisCacheModule在AppModule中导入时, 其他模块就可以直接使用,不需要再次导入由于Redis 信息写在配置文件中,所以采用registerAsync()方法来处理异步数据,如果是静态数据, 可以使用register

3、新建redis-cache.service.ts文件, 在service实现缓存的读写

内容来自samhan

1

zvvq.cn

2

zvvq好,好zvvq

3

内容来自samhan666

4 zvvq好,好zvvq

5 zvvq.cn

6

内容来自zvvq,别采集哟

7 copyright zvvq

8

内容来自samhan666

9

zvvq好,好zvvq

10 zvvq

11

内容来自zvvq,别采集哟

12

zvvq

13

内容来自zvvq

14

内容来自samhan666

15

内容来自samhan666

16 内容来自zvvq

17 zvvq.cn

18

zvvq

19

zvvq好,好zvvq

20 内容来自samhan666

import { Injectable, Inject, CACHE_MANAGER } from &39;@nestjs/common&39;; 内容来自samhan

import { Cache } from &39;cache-manager&39;; zvvq好,好zvvq

@Injectable()

zvvq.cn

export class RedisCacheService { 内容来自samhan

constructor( 内容来自samhan

@Inject(CACHE_MANAGER) zvvq.cn

private cacheManager: Cache,

copyright zvvq

) {}

本文来自zvvq

cacheSet(key: string, value: string, ttl: number) {

内容来自samhan

this.cacheManager.set(key, value, { ttl }, (err) => {

zvvq.cn

if (err) throw err;

内容来自zvvq

}); zvvq

}

内容来自samhan666

async cacheGet(key: string): Promise<any> {

内容来自samhan

return this.cacheManager.get(key); zvvq好,好zvvq

}

内容来自samhan

} 内容来自zvvq,别采集哟

接下来,在app.module.ts中导入RedisCacheModule即可。

本文来自zvvq

调整 token 签发及验证流程

我们借助redis来实现token过期处理、token自动续期、以及用户唯一登录。 内容来自zvvq

过期处理:把用户信息及token放进redis,并设置过期时间token自动续期:token的过期时间为30分钟,如果在这30分钟内没有操作,则重新登录,如果30分钟内有操作,就给token自动续一个新的时间,防止使用时掉线。户唯一登录:相同的账号,不同电脑登录,先登录的用户会被后登录的挤下线

token 过期处理

在登录时,将jwt生成的token,存入redis,并设置有效期为30分钟。存入redis的key由用户信息组成, value是token值。

zvvq好,好zvvq

1

copyright zvvq

2 内容来自zvvq,别采集哟

3 本文来自zvvq

4

本文来自zvvq

5 内容来自zvvq,别采集哟

6

内容来自samhan666

7

zvvq

8 zvvq.cn

9 内容来自samhan

10 内容来自zvvq,别采集哟

11 zvvq

12

copyright zvvq

13 zvvq.cn

14

本文来自zvvq

15

zvvq.cn

// auth.service.ts 本文来自zvvq

async login(user: Partial<User>) { 内容来自zvvq

const token = this.createToken({ 内容来自samhan

id: user.id,

zvvq好,好zvvq

username: user.username,

本文来自zvvq

role: user.role, copyright zvvq

});

zvvq好,好zvvq

+   await this.redisCacheService.cacheSet(

zvvq好,好zvvq

+     `${user.id}&${user.username}&${user.role}`, 本文来自zvvq

+     token, copyright zvvq

+     1800, 本文来自zvvq

+   );

内容来自zvvq,别采集哟

return { token };

内容来自samhan

}

内容来自zvvq,别采集哟

在验证token时, 从redis中取token,如果取不到token,可能是token已过期。

zvvq好,好zvvq

1

内容来自samhan666

2 内容来自samhan

3 内容来自zvvq,别采集哟

4

内容来自samhan666

5

本文来自zvvq

6 zvvq

7 copyright zvvq

8

本文来自zvvq

9

内容来自zvvq,别采集哟

10

zvvq

11

内容来自samhan666

12

zvvq.cn

13

内容来自zvvq

14

内容来自zvvq,别采集哟

15

内容来自samhan

16 内容来自zvvq

17

内容来自zvvq,别采集哟

18

zvvq

19

内容来自zvvq

20 copyright zvvq

21 内容来自zvvq

22 内容来自samhan

23

zvvq

24

本文来自zvvq

25

内容来自zvvq

26

copyright zvvq

27 内容来自zvvq,别采集哟

28

内容来自zvvq

29

copyright zvvq

30 内容来自zvvq

31 内容来自samhan

32

内容来自zvvq,别采集哟

33

zvvq

// jwt.strategy.ts 内容来自zvvq,别采集哟

+ import { RedisCacheService } from &39;./../core/db/redis-cache.service&39;;

内容来自zvvq

export class JwtStrategy extends PassportStrategy(Strategy) {

内容来自samhan666

constructor(

内容来自samhan666

@InjectRepository(User) copyright zvvq

private readonly userRepository: Repository<User>,

本文来自zvvq

private readonly authService: AuthService, 内容来自zvvq

private readonly configService: ConfigService,

内容来自samhan

+   private readonly redisCacheService: RedisCacheService,

内容来自samhan

) { 内容来自zvvq

super({

zvvq.cn

jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), zvvq

secretOrKey: configService.get(&39;SECRET&39;),

内容来自zvvq,别采集哟

+     passReqToCallback: true, 内容来自samhan666

} as StrategyOptions); copyright zvvq

} 本文来自zvvq

async validate(req, user: User) { 内容来自samhan

+   const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req); 内容来自samhan666

+   const cacheToken = await this.redisCacheService.cacheGet(

copyright zvvq

+     `${user.id}&${user.username}&${user.role}`,

内容来自zvvq,别采集哟

+   );

zvvq好,好zvvq

+   if (!cacheToken) {

zvvq好,好zvvq

+     throw new UnauthorizedException(&39;token 已过期&39;); copyright zvvq

+   }

内容来自zvvq,别采集哟

const existUser = await this.authService.getUser(user); copyright zvvq

if (!existUser) { 内容来自zvvq,别采集哟

throw new UnauthorizedException(&39;token不正确&39;);

本文来自zvvq

}

zvvq好,好zvvq

return existUser;

内容来自samhan666

}

内容来自samhan

}

本文来自zvvq

用户唯一登录

当用户登录时,每次签发的新的token,会覆盖之前的token, 判断redis中的token与请求传入的token是否相同, 不相同时, 可能是其他地方已登录, 提示token错误。 copyright zvvq

1

本文来自zvvq

2

内容来自samhan666

3

copyright zvvq

4

内容来自samhan

5 内容来自zvvq,别采集哟

6 zvvq.cn

7 zvvq

8 内容来自zvvq

9 zvvq好,好zvvq

10

内容来自samhan666

11 内容来自samhan666

12 内容来自zvvq,别采集哟

13

内容来自samhan666

14 copyright zvvq

15 zvvq

16

zvvq.cn

17

内容来自zvvq

18 内容来自zvvq

// jwt.strategy.ts 内容来自zvvq

async validate(req, user: User) { 内容来自zvvq,别采集哟

const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req); zvvq好,好zvvq

const cacheToken = await this.redisCacheService.cacheGet( 内容来自samhan666

`${user.id}&${user.username}&${user.role}`,

zvvq好,好zvvq

); copyright zvvq

if (!cacheToken) {

本文来自zvvq

throw new UnauthorizedException(&39;token 已过期&39;);

内容来自samhan

} 内容来自samhan

+   if (token != cacheToken) {

内容来自zvvq,别采集哟

+     throw new UnauthorizedException(&39;token不正确&39;); zvvq.cn

+   } copyright zvvq

const existUser = await this.authService.getUser(user); 本文来自zvvq

if (!existUser) {

zvvq好,好zvvq

throw new UnauthorizedException(&39;token不正确&39;); 内容来自samhan

}

内容来自samhan

return existUser;

zvvq好,好zvvq

} zvvq好,好zvvq

token自动续期

实现方案有多种,可以后台jwt生成access_token(jwt有效期30分钟)和refresh_token, refresh_token有效期比access_token有效期长,客户端缓存此两种token, 当access_token过期时, 客户端再携带refresh_token获取新的access_token。 这种方案需要接口调用的开发人员配合。 copyright zvvq

我这里主要介绍一下,纯后端实现的token自动续期

zvvq好,好zvvq

实现流程:

zvvq好,好zvvq

①:jwt生成token时,有效期设置为用不过期②:redis 缓存token时设置有效期30分钟③:用户携带token请求时, 如果key存在,且value相同, 则重新设置有效期为30分钟

设置jwt生成的token, 用不过期, 这部分代码是在auth.module.ts文件中, 不了解的可以看文章 Nest.js 实战系列第二篇-实现注册、扫码登陆、jwt认证 zvvq.cn

1 copyright zvvq

2 zvvq好,好zvvq

3 内容来自zvvq,别采集哟

4

内容来自zvvq

5

zvvq好,好zvvq

6 zvvq

7 内容来自zvvq,别采集哟

8

本文来自zvvq

9

内容来自samhan

10 zvvq

// auth.module.ts

zvvq

const jwtModule = JwtModule.registerAsync({

copyright zvvq

inject: [ConfigService], 内容来自zvvq,别采集哟

useFactory: async (configService: ConfigService) => { 内容来自samhan666

return { 内容来自samhan

secret: configService.get(&39;SECRET&39;, &39;test123456&39;),

zvvq好,好zvvq

-     signOptions: { expiresIn: &39;4h&39; },  // 取消有效期设置

zvvq.cn

};

内容来自samhan666

}, 本文来自zvvq

}); 本文来自zvvq

然后再token认证通过后,重新设置过期时间, 因为使用的cache-manager没有通过直接更新有效期方法,通过重新设置来实现:

zvvq

1 内容来自zvvq,别采集哟

2

内容来自samhan666

3 zvvq好,好zvvq

4

copyright zvvq

5

内容来自samhan666

6

内容来自zvvq,别采集哟

7 zvvq好,好zvvq

8

内容来自zvvq

9

内容来自zvvq,别采集哟

10 zvvq好,好zvvq

11 zvvq好,好zvvq

12 内容来自zvvq

13 zvvq

14 zvvq

15

内容来自samhan

16

zvvq好,好zvvq

17 本文来自zvvq

18 内容来自zvvq

19 zvvq.cn

20

zvvq好,好zvvq

21 内容来自samhan666

22 zvvq

23 copyright zvvq

// jwt.strategy.ts 本文来自zvvq

async validate(req, user: User) {

内容来自zvvq

const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req);

内容来自samhan

const cacheToken = await this.redisCacheService.cacheGet( 内容来自samhan

`${user.id}&${user.username}&${user.role}`,

zvvq.cn

); 本文来自zvvq

if (!cacheToken) { copyright zvvq

throw new UnauthorizedException(&39;token 已过期&39;); zvvq

}

内容来自samhan

if (token != cacheToken) { 内容来自zvvq

throw new UnauthorizedException(&39;token不正确&39;); zvvq

}

zvvq好,好zvvq

const existUser = await this.authService.getUser(user);

zvvq.cn

if (!existUser) {

copyright zvvq

throw new UnauthorizedException(&39;token不正确&39;); zvvq好,好zvvq

} 内容来自samhan666

+   this.redisCacheService.cacheSet(

内容来自zvvq

+     `${user.id}&${user.username}&${user.role}`,

copyright zvvq

+     token, 内容来自zvvq

+     1800,

内容来自samhan666

+   ); 内容来自samhan

return existUser;

copyright zvvq

} zvvq.cn

到此,在Nest中实现token过期处理、token自动续期、以及用户唯一登录都完成了, 退出登录时移除token比较简单就不在这里一一上代码了。 copyright zvvq

在Nest中除了使用官方推荐的这种方式外, 还可以使用nestjs-redis来实现,如果你存token时, 希望存hash结构,使用cache-manager-redis-store时,会发现没有提供hash值存取放方法(需要花点心思去发现)。 zvvq.cn

注意:如果使用nest-redis来实现redis缓存, 在Nest.js 8 版本下会报错, 小伙伴们可以使用@chenjm/nestjs-redis 来代替, 或者参考 issue上的解决方案:Nest 8 + redis bug。

总结

源码地址:https://github.com/koala-coding/nest-blog zvvq

更多编程相关知识,请访问:编程教学!! 本文来自zvvq

以上就是Node.js中怎么使用Redis?原来这么简单!的详细内容,更多请关注其它相关文章!

zvvq