91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Node.js中如何使用Redis

發布時間:2022-11-08 10:10:03 來源:億速云 閱讀:142 作者:iii 欄目:web開發

這篇文章主要介紹了Node.js中如何使用Redis的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Node.js中如何使用Redis文章都會有所收獲,下面我們一起來看看吧。

1. 認識redis

對于前端的小伙伴來說,Redis可能相對比較陌生,首先認識一下

Redis是什么

Redis是一個開源(BSD許可)的,基于內存的數據結構存儲系統,它可以用作數據庫、緩存和消息中間件,是現在最受歡迎的 NoSQL 數據庫之一。

其具備如下特性:

  • 速度快

    • 單節點讀110000次/s,寫81000次/s

    • 基于內存運行,性能高效

    • 用 C 語言實現,離操作系統更近

  • 持久化

    • 數據的更新將異步地保存到硬盤(RDB 和 AOF

  • 多種數據結構

    • 不僅僅支持簡單的 key-value 類型數據

    • 還支持:字符串、hash、列表、集合、有序集合

  • 支持多種編程語言等等

Redis 典型使用場景

緩存

緩存可以說是Redis最常用的功能之一了, 合理的緩存不僅可以加快訪問的速度,也可以減少后端數據庫的壓力。

排行系統

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

計數器應用

計數器的應用基本和排行榜系統一樣,都是多數網站的普遍需求,如視頻網站的播放計數,電商網站的瀏覽數等等,但這些數量一般比較龐大,如果存到關系型數據庫,對MySQL或者其他關系型數據庫的挑戰還是很大的,而Redis基本可以說是天然支持計數器應用。

(視頻直播)消息彈幕

直播間的在線用戶列表,禮物排行榜,彈幕消息等信息,都適合使用Redis中的SortedSet結構進行存儲。

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

Redis的應用場景遠不止這些,Redis對傳統磁盤數據庫是一個重要的補充,是支持高并發訪問的互聯網應用必不可少的基礎服務之一。

紙上談兵終覺淺,必須實戰一波~

Redis的安裝和簡單使用,我這里就不一一介紹了,這里貼上我之前寫的兩篇文章:

  • Redis 安裝

  • Redis入門篇-基礎使用

可以快速的安裝、了解Redis數據類型以及常用的命令。

可視化客戶端

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

下載后直接雙擊redisclient-win32.x86.2.0.exe文件運行即可

Node.js中如何使用Redis

啟動后, 點擊server -> add

Node.js中如何使用Redis

連接后就可以看到總體情況了:

Node.js中如何使用Redis

與SQL型數據不同,redis沒有提供新建數據庫的操作,因為它自帶了16(0-15)個數據庫(默認使用0庫)。在同一個庫中,key是唯一存在的、不允許重復的,它就像一把“密鑰”,只能打開一把“鎖”。鍵值存儲的本質就是使用key來標識value,當想要檢索value時,必須使用與value對應的key進行查找.

2. 在Nest.js中使用

版本情況:

版本
Nest.jsV8.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配置文件中:

Node.js中如何使用Redis

使用Nest官方推薦的方法,只需要簡單的3個步驟:

1、引入依賴文件

npm install cache-manager --save
npm install cache-manager-redis-store --save
npm install @types/cache-manager -D

登錄后復制

Nest為各種緩存存儲提供統一的API,內置的是內存中的數據存儲,但是也可使用 cache-manager來使用其他方案, 比如使用Redis來緩存。

為了啟用緩存, 導入ConfigModule, 并調用register()或者registerAsync()傳入響應的配置參數。

2、創建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 {}

  • CacheModuleregisterAsync方法采用 Redis Store 配置進行通信

  • store 屬性值redisStore ,表示'cache-manager-redis-store' 庫

  • isGlobal 屬性設置為true 來將其聲明為全局模塊,當我們將RedisCacheModuleAppModule中導入時, 其他模塊就可以直接使用,不需要再次導入

  • 由于Redis 信息寫在配置文件中,所以采用registerAsync()方法來處理異步數據,如果是靜態數據, 可以使用register

3、新建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即可。

調整 token 簽發及驗證流程

我們借助redis來實現token過期處理、token自動續期、以及用戶唯一登錄。

  • 過期處理:把用戶信息及token放進redis,并設置過期時間

  • token自動續期:token的過期時間為30分鐘,如果在這30分鐘內沒有操作,則重新登錄,如果30分鐘內有操作,就給token自動續一個新的時間,防止使用時掉線。

  • 戶唯一登錄:相同的賬號,不同電腦登錄,先登錄的用戶會被后登錄的擠下線

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;
  }

token自動續期

實現方案有多種,可以后臺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.ts
const 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”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

全州县| 定结县| 科尔| 临安市| 天全县| 类乌齐县| 晋江市| 兴仁县| 九江县| 吴堡县| 仙游县| 金阳县| 五家渠市| 固镇县| 璧山县| 凌源市| 井研县| 黄大仙区| 呼伦贝尔市| 河间市| 宿迁市| 姜堰市| 宁波市| 海林市| 绥棱县| 阿拉善左旗| 长垣县| 南平市| 达尔| 绵阳市| 登封市| 吉林省| 海原县| 旺苍县| 玉环县| 大同县| 三原县| 抚顺市| 尼木县| 淮南市| 海南省|