這篇文章主要介紹了Node.js中如何使用redis的相關(guān)知識,內(nèi)容詳細(xì)易懂,操作簡單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇Node.js中如何使用Redis文章都會有所收獲,下面我們一起來看看吧。
創(chuàng)新互聯(lián)公司-成都網(wǎng)站建設(shè)公司,專注網(wǎng)站制作、做網(wǎng)站、網(wǎng)站營銷推廣,空間域名,網(wǎng)站空間,網(wǎng)站托管維護(hù)有關(guān)企業(yè)網(wǎng)站制作方案、改版、費(fèi)用等問題,請聯(lián)系創(chuàng)新互聯(lián)公司。
對于前端的小伙伴來說,Redis可能相對比較陌生,首先認(rèn)識一下
Redis是一個(gè)開源(BSD許可)的,基于內(nèi)存的數(shù)據(jù)結(jié)構(gòu)存儲系統(tǒng),它可以用作數(shù)據(jù)庫、緩存和消息中間件,是現(xiàn)在最受歡迎的 NOSQL 數(shù)據(jù)庫之一。
其具備如下特性:
速度快
單節(jié)點(diǎn)讀110000次/s,寫81000次/s
基于內(nèi)存運(yùn)行,性能高效
用 C 語言實(shí)現(xiàn),離操作系統(tǒng)更近
持久化
數(shù)據(jù)的更新將異步地保存到硬盤(RDB 和 AOF
多種數(shù)據(jù)結(jié)構(gòu)
不僅僅支持簡單的 key-value 類型數(shù)據(jù)
還支持:字符串、hash、列表、集合、有序集合
支持多種編程語言等等
緩存
緩存可以說是Redis最常用的功能之一了, 合理的緩存不僅可以加快訪問的速度,也可以減少后端數(shù)據(jù)庫的壓力。
排行系統(tǒng)
利用Redis的列表和有序集合的特點(diǎn),可以制作排行榜系統(tǒng),而排行榜系統(tǒng)目前在商城類、新聞類、博客類等等,都是比不可缺的。
計(jì)數(shù)器應(yīng)用
計(jì)數(shù)器的應(yīng)用基本和排行榜系統(tǒng)一樣,都是多數(shù)網(wǎng)站的普遍需求,如視頻網(wǎng)站的播放計(jì)數(shù),電商網(wǎng)站的瀏覽數(shù)等等,但這些數(shù)量一般比較龐大,如果存到關(guān)系型數(shù)據(jù)庫,對MySQL或者其他關(guān)系型數(shù)據(jù)庫的挑戰(zhàn)還是很大的,而Redis基本可以說是天然支持計(jì)數(shù)器應(yīng)用。
(視頻直播)消息彈幕
直播間的在線用戶列表,禮物排行榜,彈幕消息等信息,都適合使用Redis中的SortedSet結(jié)構(gòu)進(jìn)行存儲。
例如彈幕消息,可使用ZREVRANGEBYSCORE
排序返回,在Redis5.0中,新增了zpopmax
,zpopmin
命令,更加方便消息處理。
Redis的應(yīng)用場景遠(yuǎn)不止這些,Redis對傳統(tǒng)磁盤數(shù)據(jù)庫是一個(gè)重要的補(bǔ)充,是支持高并發(fā)訪問的互聯(lián)網(wǎng)應(yīng)用必不可少的基礎(chǔ)服務(wù)之一。
紙上談兵終覺淺,必須實(shí)戰(zhàn)一波~
Redis的安裝和簡單使用,我這里就不一一介紹了,這里貼上我之前寫的兩篇文章:
Redis 安裝
Redis入門篇-基礎(chǔ)使用
可以快速的安裝、了解Redis數(shù)據(jù)類型以及常用的命令。
在Windows下使用 RedisClient, 在mac下可以使用Redis Desktop Manager
下載后直接雙擊redisclient-win32.x86.2.0.exe
文件運(yùn)行即可
啟動后, 點(diǎn)擊server -> add
連接后就可以看到總體情況了:
與SQL型數(shù)據(jù)不同,redis沒有提供新建數(shù)據(jù)庫的操作,因?yàn)樗詭Я?6(0-15)個(gè)數(shù)據(jù)庫(默認(rèn)使用0庫)。在同一個(gè)庫中,key是唯一存在的、不允許重復(fù)的,它就像一把“密鑰”,只能打開一把“鎖”。鍵值存儲的本質(zhì)就是使用key來標(biāo)識value,當(dāng)想要檢索value時(shí),必須使用與value對應(yīng)的key進(jìn)行查找.
版本情況:
庫 | 版本 |
---|---|
Nest.js | V8.1.2 |
項(xiàng)目是基于Nest.js 8.x
版本,與Nest.js 9.x
版本使用有所不同, 后面的文章專門整理了兩個(gè)版本使用不同點(diǎn)的說明, 以及如何從V8
升級到V9
, 這里就不過多討論。
首先,我們在Nest.js項(xiàng)目中連接Redis, 連接Redis需要的參數(shù):
REDIS_HOST:Redis 域名
REDIS_PORT:Redis 端口號
REDIS_DB: Redis 數(shù)據(jù)庫
REDIS_PASSPORT:Redis 設(shè)置的密碼
將參數(shù)寫入.env
與.env.prod
配置文件中:
使用Nest官方推薦的方法,只需要簡單的3個(gè)步驟:
1、引入依賴文件
登錄后復(fù)制npm install cache-manager --save
npm install cache-manager-redis-store --save
npm install @types/cache-manager -D
Nest
為各種緩存存儲提供統(tǒng)一的API,內(nèi)置的是內(nèi)存中的數(shù)據(jù)存儲,但是也可使用 cache-manager
來使用其他方案, 比如使用Redis
來緩存。
為了啟用緩存, 導(dǎo)入ConfigModule
, 并調(diào)用register()
或者registerAsync()
傳入響應(yīng)的配置參數(shù)。
2、創(chuàng)建module文件src/db/redis-cache.module.ts
, 實(shí)現(xiàn)如下:
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, //目標(biāo)庫,
auth_pass: configService.get('REDIS_PASSPORT') // 密碼,沒有可以不寫
};
},
}),
],
providers: [RedisCacheService],
exports: [RedisCacheService],
})
export class RedisCacheModule {}
CacheModule
的registerAsync
方法采用 Redis Store 配置進(jìn)行通信
store
屬性值redisStore
,表示'cache-manager-redis-store' 庫
isGlobal
屬性設(shè)置為true
來將其聲明為全局模塊,當(dāng)我們將RedisCacheModule
在AppModule
中導(dǎo)入時(shí), 其他模塊就可以直接使用,不需要再次導(dǎo)入
由于Redis 信息寫在配置文件中,所以采用registerAsync()
方法來處理異步數(shù)據(jù),如果是靜態(tài)數(shù)據(jù), 可以使用register
3、新建redis-cache.service.ts
文件, 在service實(shí)現(xiàn)緩存的讀寫
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
中導(dǎo)入RedisCacheModule
即可。
我們借助redis來實(shí)現(xiàn)token過期處理、token自動續(xù)期、以及用戶唯一登錄。
過期處理:把用戶信息及token放進(jìn)redis,并設(shè)置過期時(shí)間
token自動續(xù)期:token的過期時(shí)間為30分鐘,如果在這30分鐘內(nèi)沒有操作,則重新登錄,如果30分鐘內(nèi)有操作,就給token自動續(xù)一個(gè)新的時(shí)間,防止使用時(shí)掉線。
戶唯一登錄:相同的賬號,不同電腦登錄,先登錄的用戶會被后登錄的擠下線
在登錄時(shí),將jwt生成的token,存入redis,并設(shè)置有效期為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 };
}
在驗(yàn)證token時(shí), 從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;
}
}
當(dāng)用戶登錄時(shí),每次簽發(fā)的新的token,會覆蓋之前的token, 判斷redis中的token與請求傳入的token是否相同, 不相同時(shí), 可能是其他地方已登錄, 提示token錯(cuò)誤。
// 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;
}
實(shí)現(xiàn)方案有多種,可以后臺jwt生成access_token
(jwt有效期30分鐘)和refresh_token
, refresh_token
有效期比access_token
有效期長,客戶端緩存此兩種token, 當(dāng)access_token
過期時(shí), 客戶端再攜帶refresh_token
獲取新的access_token
。 這種方案需要接口調(diào)用的開發(fā)人員配合。
我這里主要介紹一下,純后端實(shí)現(xiàn)的token自動續(xù)期
實(shí)現(xiàn)流程:
①:jwt生成token時(shí),有效期設(shè)置為用不過期
②:redis 緩存token時(shí)設(shè)置有效期30分鐘
③:用戶攜帶token請求時(shí), 如果key存在,且value相同, 則重新設(shè)置有效期為30分鐘
設(shè)置jwt生成的token, 用不過期, 這部分代碼是在auth.module.ts
文件中, 不了解的可以看文章 Nest.js 實(shí)戰(zhàn)系列第二篇-實(shí)現(xiàn)注冊、掃碼登陸、jwt認(rèn)證
// auth.module.ts
const jwtModule = JwtModule.registerAsync({
inject: [ConfigService],
useFactory: async (configService: ConfigService) => {
return {
secret: configService.get('SECRET', 'test123456'),
- signOptions: { expiresIn: '4h' }, // 取消有效期設(shè)置
};
},
});
然后再token認(rèn)證通過后,重新設(shè)置過期時(shí)間, 因?yàn)槭褂玫?code>cache-manager沒有通過直接更新有效期方法,通過重新設(shè)置來實(shí)現(xiàn):
// 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
來實(shí)現(xiàn),如果你存token時(shí), 希望存hash
結(jié)構(gòu),使用cache-manager-redis-store
時(shí),會發(fā)現(xiàn)沒有提供hash
值存取放方法(需要花點(diǎn)心思去發(fā)現(xiàn))。
注意:如果使用
nest-redis
來實(shí)現(xiàn)redis緩存, 在Nest.js 8 版本下會報(bào)錯(cuò), 小伙伴們可以使用@chenjm/nestjs-redis
來代替, 或者參考 issue上的解決方案:Nest 8 + redis bug。
關(guān)于“Node.js中如何使用Redis”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“Node.js中如何使用Redis”知識都有一定的了解,大家如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
當(dāng)前名稱:Node.js中如何使用Redis
URL地址:http://bm7419.com/article16/pphdgg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)公司、云服務(wù)器、微信公眾號、網(wǎng)站設(shè)計(jì)、域名注冊、網(wǎng)站收錄
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)