这篇文章主要介绍了node.js中如何使用Redis的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇node.js中如何使用Redis文章都会有所收获,下面我们一起来看看吧。1. 认识redis对于前端的小伙伴来
这篇文章主要介绍了node.js中如何使用Redis的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇node.js中如何使用Redis文章都会有所收获,下面我们一起来看看吧。
对于前端的小伙伴来说,Redis可能相对比较陌生,首先认识一下
Redis是一个开源(BSD许可)的,基于内存的数据结构存储系统,它可以用作数据库、缓存和消息中间件,是现在最受欢迎的 NoSQL 数据库之一。
其具备如下特性:
缓存
缓存可以说是Redis最常用的功能之一了, 合理的缓存不仅可以加快访问的速度,也可以减少后端数据库的压力。
排行系统
利用Redis的列表和有序集合的特点,可以制作排行榜系统,而排行榜系统目前在商城类、新闻类、博客类等等,都是比不可缺的。
计数器应用
计数器的应用基本和排行榜系统一样,都是多数网站的普遍需求,如视频网站的播放计数,电商网站的浏览数等等,但这些数量一般比较庞大,如果存到关系型数据库,对MySQL或者其他关系型数据库的挑战还是很大的,而Redis基本可以说是天然支持计数器应用。
(视频直播)消息弹幕
直播间的在线用户列表,礼物排行榜,弹幕消息等信息,都适合使用Redis中的SortedSet结构进行存储。
例如弹幕消息,可使用ZREVRANGEBYSCORE
排序返回,在Redis5.0中,新增了zpopmax
,zpopmin
命令,更加方便消息处理。
Redis的应用场景远不止这些,Redis对传统磁盘数据库是一个重要的补充,是支持高并发访问的互联网应用必不可少的基础服务之一。
纸上谈兵终觉浅,必须实战一波~
Redis的安装和简单使用,我这里就不一一介绍了,这里贴上我之前写的两篇文章:
Redis 安装
Redis入门篇-基础使用
可以快速的安装、了解Redis数据类型以及常用的命令。
在windows下使用 RedisClient, 在Mac下可以使用Redis Desktop Manager
下载后直接双击redisclient-win32.x86.2.0.exe
文件运行即可
启动后, 点击server -> add
连接后就可以看到总体情况了:
与sql型数据不同,redis没有提供新建数据库的操作,因为它自带了16(0-15)个数据库(默认使用0库)。在同一个库中,key是唯一存在的、不允许重复的,它就像一把“密钥”,只能打开一把“锁”。键值存储的本质就是使用key来标识value,当想要检索value时,必须使用与value对应的key进行查找.
版本情况:
库 | 版本 |
---|---|
Nest.js | V8.1.2 |
项目是基于Nest.js 8.x
版本,与Nest.js 9.x
版本使用有所不同, 后面的文章专门整理了两个版本使用不同点的说明, 以及如何从V8
升级到V9
, 这里就不过多讨论。
首先,我们在Nest.js项目中连接Redis, 连接Redis需要的参数:
REDIS_HOST:Redis 域名REDIS_PORT:Redis 端口号REDIS_DB: Redis 数据库REDIS_PASSPORT:Redis 设置的密码
将参数写入.env
与.env.prod
配置文件中:
使用Nest官方推荐的方法,只需要简单的3个步骤:
引入依赖文件
登录后复制npm install cache-manager --savenpm install cache-manager-redis-store --savenpm install @types/cache-manager -D
Nest
为各种缓存存储提供统一的api,内置的是内存中的数据存储,但是也可使用 cache-manager
来使用其他方案, 比如使用Redis
来缓存。
为了启用缓存, 导入ConfigModule
, 并调用reGISter()
或者registerAsync()
传入响应的配置参数。
创建module文件src/db/redis-cache.module.ts
, 实现如下:
import { ConfigModule, ConfigService } from '@nestjs/config';import { RedisCacheService } from './redis-cache.service';import { CacheModule, Module, Global } from '@nestjs/common';import * as redisStore from 'cache-manager-redis-store';@Module({ imports: [ CacheModule.registerAsync({ isGlobal: true, imports: [ConfigModule], inject: [ConfigService], useFactory: async (configService: ConfigService) => { return { store: redisStore, host: configService.get('REDIS_HOST'), port: configService.get('REDIS_PORT'), db: 0, //目标库, auth_pass: configService.get('REDIS_PASSPORT') // 密码,没有可以不写 }; }, }), ], providers: [RedisCacheService], exports: [RedisCacheService],})export class RedisCacheModule {}
CacheModule
的registerAsync
方法采用 Redis Store 配置进行通信
store
属性值redisStore
,表示'cache-manager-redis-store' 库
isGlobal
属性设置为true
来将其声明为全局模块,当我们将RedisCacheModule
在AppModule
中导入时, 其他模块就可以直接使用,不需要再次导入
由于Redis 信息写在配置文件中,所以采用registerAsync()
方法来处理异步数据,如果是静态数据, 可以使用register
新建redis-cache.service.ts
文件, 在service实现缓存的读写
import { Injectable, Inject, CACHE_MANAGER } from '@nestjs/common';import { Cache } from 'cache-manager';@Injectable()export class RedisCacheService { constructor( @Inject(CACHE_MANAGER) private cacheManager: Cache, ) {} cacheSet(key: string, value: string, ttl: number) { this.cacheManager.set(key, value, { ttl }, (err) => { if (err) throw err; }); } async cacheGet(key: string): Promise<any> { return this.cacheManager.get(key); }}
接下来,在app.module.ts
中导入RedisCacheModule
即可。
我们借助redis来实现token过期处理、token自动续期、以及用户唯一登录。
过期处理:把用户信息及token放进redis,并设置过期时间
token自动续期:token的过期时间为30分钟,如果在这30分钟内没有操作,则重新登录,如果30分钟内有操作,就给token自动续一个新的时间,防止使用时掉线。
户唯一登录:相同的账号,不同电脑登录,先登录的用户会被后登录的挤下线
在登录时,将Jwt生成的token,存入redis,并设置有效期为30分钟。存入redis的key由用户信息组成, value是token值。
// auth.service.ts async login(user: Partial<User>) { const token = this.createToken({ id: user.id, username: user.username, role: user.role, });+ await this.redisCacheService.cacheSet(+ `${user.id}&${user.username}&${user.role}`,+ token,+ 1800,+ ); return { token }; }
在验证token时, 从redis中取token,如果取不到token,可能是token已过期。
// jwt.strategy.ts+ import { RedisCacheService } from './../core/db/redis-cache.service';export class JwtStrategy extends PassportStrategy(Strategy) { constructor( @InjectRepository(User) private readonly userRepository: Repository<User>, private readonly authService: AuthService, private readonly configService: ConfigService,+ private readonly redisCacheService: RedisCacheService, ) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: configService.get('SECRET'),+ passReQtoCallback: true, } as StrategyOptions); } async validate(req, user: User) {+ const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req);+ const cacheToken = await this.redisCacheService.cacheGet(+ `${user.id}&${user.username}&${user.role}`,+ );+ if (!cacheToken) {+ throw new UnauthorizedException('token 已过期');+ } const existUser = await this.authService.getUser(user); if (!existUser) { throw new UnauthorizedException('token不正确'); } return existUser; }}
当用户登录时,每次签发的新的token,会覆盖之前的token, 判断redis中的token与请求传入的token是否相同, 不相同时, 可能是其他地方已登录, 提示token错误。
// jwt.strategy.ts async validate(req, user: User) { const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req); const cacheToken = await this.redisCacheService.cacheGet( `${user.id}&${user.username}&${user.role}`, ); if (!cacheToken) { throw new UnauthorizedException('token 已过期'); }+ if (token != cacheToken) {+ throw new UnauthorizedException('token不正确');+ } const existUser = await this.authService.getUser(user); if (!existUser) { throw new UnauthorizedException('token不正确'); } return existUser; }
实现方案有多种,可以后台jwt生成access_token
(jwt有效期30分钟)和refresh_token
, refresh_token
有效期比access_token
有效期长,客户端缓存此两种token, 当access_token
过期时, 客户端再携带refresh_token
获取新的access_token
。 这种方案需要接口调用的开发人员配合。
我这里主要介绍一下,纯后端实现的token自动续期
实现流程:
①:jwt生成token时,有效期设置为用不过期
②:redis 缓存token时设置有效期30分钟
③:用户携带token请求时, 如果key存在,且value相同, 则重新设置有效期为30分钟
设置jwt生成的token, 用不过期, 这部分代码是在auth.module.ts
文件中, 不了解的可以看文章 Nest.js 实战系列第二篇-实现注册、扫码登陆、jwt认证
// auth.module.tsconst jwtModule = JwtModule.registerAsync({ inject: [ConfigService], useFactory: async (configService: ConfigService) => { return { secret: configService.get('SECRET', 'test123456'),- signOptions: { expiresIn: '4h' }, // 取消有效期设置 }; },});
然后再token认证通过后,重新设置过期时间, 因为使用的cache-manager
没有通过直接更新有效期方法,通过重新设置来实现:
// jwt.strategy.ts async validate(req, user: User) { const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req); const cacheToken = await this.redisCacheService.cacheGet( `${user.id}&${user.username}&${user.role}`, ); if (!cacheToken) { throw new UnauthorizedException('token 已过期'); } if (token != cacheToken) { throw new UnauthorizedException('token不正确'); } const existUser = await this.authService.getUser(user); if (!existUser) { throw new UnauthorizedException('token不正确'); }+ this.redisCacheService.cacheSet(+ `${user.id}&${user.username}&${user.role}`,+ token,+ 1800,+ ); return existUser; }
在Nest中除了使用官方推荐的这种方式外, 还可以使用nestjs-redis
来实现,如果你存token时, 希望存hash
结构,使用cache-manager-redis-store
时,会发现没有提供hash
值存取放方法(需要花点心思去发现)。
注意:如果使用
nest-redis
来实现redis缓存, 在Nest.js 8 版本下会报错, 小伙伴们可以使用@chenjm/nestjs-redis
来代替, 或者参考 issue上的解决方案:Nest 8 + redis bug。
关于“Node.js中如何使用Redis”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Node.js中如何使用Redis”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网精选频道。
--结束END--
本文标题: Node.js中如何使用Redis
本文链接: https://lsjlt.com/news/345427.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0