搜尋
首頁web前端js教程Node.js中怎麼使用Redis?原來這麼簡單!

Node.js中怎麼使用Redis?原來這麼簡單!

Nov 07, 2022 pm 08:04 PM
javascript前端node.js

Node中怎麼使用Redis?以下這篇文章跟大家介紹一下Node.js中使用Redis的方法,你會發現原來這麼簡單,希望對大家有幫助!

Node.js中怎麼使用Redis?原來這麼簡單!

之前的文章中我們其實留了兩個可以用redis優化的地方:

  • 一個是我們的在做登入時,透過JWT已經實作了服務端產生token以及驗證客戶端發送的token訊息。 【相關教學推薦:nodejs影片教學 、程式設計影片
  • 實作文章按讚功能,採用的是將按讚資料直接寫入資料庫

JWT token 實作方式, 將基本資訊直接放在token中,以便於分散式系統使用, 但是我們沒有設定有限期(這個是可以實現的),且服務端無法主動讓token失效。而Redis天然支援過期時間,也能實現讓服務端主動使token過期。

當然不是說JWT token 不如 redis token實作方案好, 具體看使用的場景,這裡我們並不討論二者孰優孰劣,只是提供一種實現方案,讓大家知道如何實現。

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資料型別以及常用的命令。

視覺化客戶端

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

RedisClient下載連結:https://github.com/caoxinyu/RedisClient

下載後直接雙擊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進行查找.

Redis 認識作為文章前置條件,到這裡及結束了, 接下來進入正題~

本文主要使用Redis實作快取功能。

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 &#39;./../core/db/redis-cache.service&#39;;

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(&#39;SECRET&#39;),
+     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(&#39;token 已过期&#39;);
+   }
    const existUser = await this.authService.getUser(user);
    if (!existUser) {
      throw new UnauthorizedException(&#39;token不正确&#39;);
    }
    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(&#39;token 已过期&#39;);
    }
+   if (token != cacheToken) {
+     throw new UnauthorizedException(&#39;token不正确&#39;);
+   }
    const existUser = await this.authService.getUser(user);
    if (!existUser) {
      throw new UnauthorizedException(&#39;token不正确&#39;);
    }
    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(&#39;SECRET&#39;, &#39;test123456&#39;),
-     signOptions: { expiresIn: &#39;4h&#39; },  // 取消有效期设置
    };
  },
});

然後再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(&#39;token 已过期&#39;);
    }
    if (token != cacheToken) {
      throw new UnauthorizedException(&#39;token不正确&#39;);
    }
    const existUser = await this.authService.getUser(user);
    if (!existUser) {
      throw new UnauthorizedException(&#39;token不正确&#39;);
    }
+   this.redisCacheService.cacheSet(
+     `${user.id}&${user.username}&${user.role}`,
+     token,
+     1800,
+   );
    return existUser;
  }

到此,在Nest中實現token過期處理、token自動續期、以及用戶唯一登入都完成了, 登出登入時移除token比較簡單就不在這裡一一上代碼了。

在Nest中除了使用官方推薦的這種方式外, 還可以使用

nestjs-redis來實現,如果你存token時, 希望存hash結構,使用cache-manager-redis-store時,會發現沒有提供hash值存取放方法(需要花點心思去發現)。

注意:如果使用nest-redis來實現redis緩存, 在Nest.js 8 版本下會報錯, 小夥伴可以使用@chenjm/nestjs-redis 來代替, 或參考issue上的解決方案:Nest 8 redis bug

總結

原始碼位址:https://github.com/koala-coding/nest-blog

#更多程式相關知識,請訪問:程式設計教學! !

以上是Node.js中怎麼使用Redis?原來這麼簡單!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:掘金社区。如有侵權,請聯絡admin@php.cn刪除
JavaScript是用C編寫的嗎?檢查證據JavaScript是用C編寫的嗎?檢查證據Apr 25, 2025 am 12:15 AM

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript的角色:使網絡交互和動態JavaScript的角色:使網絡交互和動態Apr 24, 2025 am 12:12 AM

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C和JavaScript:連接解釋C和JavaScript:連接解釋Apr 23, 2025 am 12:07 AM

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

從網站到應用程序:JavaScript的不同應用從網站到應用程序:JavaScript的不同應用Apr 22, 2025 am 12:02 AM

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python vs. JavaScript:比較用例和應用程序Python vs. JavaScript:比較用例和應用程序Apr 21, 2025 am 12:01 AM

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C/C在JavaScript口譯員和編譯器中的作用C/C在JavaScript口譯員和編譯器中的作用Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在行動中:現實世界中的示例和項目JavaScript在行動中:現實世界中的示例和項目Apr 19, 2025 am 12:13 AM

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中