目錄
1. 認識redis
Redis是什麼
#Redis 典型使用場景
視覺化客戶端
2. 在Nest.js中使用
調整 token 簽發及驗證流程
用戶唯一登入
token自動續期
總結
首頁 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

熱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

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

熱工具

記事本++7.3.1

記事本++7.3.1

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

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

PHP與Vue:完美搭檔的前端開發利器 PHP與Vue:完美搭檔的前端開發利器 Mar 16, 2024 pm 12:09 PM

PHP與Vue:完美搭檔的前端開發利器在當今網路快速發展的時代,前端開發變得愈發重要。隨著使用者對網站和應用的體驗要求越來越高,前端開發人員需要使用更有效率和靈活的工具來創建響應式和互動式的介面。 PHP和Vue.js作為前端開發領域的兩個重要技術,搭配起來可以稱得上是完美的利器。本文將探討PHP和Vue的結合,以及詳細的程式碼範例,幫助讀者更好地理解和應用這兩

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

Django是前端還是後端?一探究竟! Django是前端還是後端?一探究竟! Jan 19, 2024 am 08:37 AM

Django是一個由Python編寫的web應用框架,它強調快速開發和乾淨方法。儘管Django是web框架,但要回答Django是前端還是後端這個問題,需要深入理解前後端的概念。前端是指使用者直接和互動的介面,後端是指伺服器端的程序,他們透過HTTP協定進行資料的互動。在前端和後端分離的情況下,前後端程式可以獨立開發,分別實現業務邏輯和互動效果,資料的交

前端面試官常問的問題 前端面試官常問的問題 Mar 19, 2024 pm 02:24 PM

在前端開發面試中,常見問題涵蓋廣泛,包括HTML/CSS基礎、JavaScript基礎、框架和函式庫、專案經驗、演算法和資料結構、效能最佳化、跨域請求、前端工程化、設計模式以及新技術和趨勢。面試官的問題旨在評估候選人的技術技能、專案經驗以及對行業趨勢的理解。因此,應試者應充分準備這些方面,以展現自己的能力和專業知識。

Go語言前端技術探秘:前端開發新視野 Go語言前端技術探秘:前端開發新視野 Mar 28, 2024 pm 01:06 PM

Go語言作為一種快速、高效的程式語言,在後端開發領域廣受歡迎。然而,很少有人將Go語言與前端開發聯繫起來。事實上,使用Go語言進行前端開發不僅可以提高效率,還能為開發者帶來全新的視野。本文將探討使用Go語言進行前端開發的可能性,並提供具體的程式碼範例,幫助讀者更了解這一領域。在傳統的前端開發中,通常會使用JavaScript、HTML和CSS來建立使用者介面

Django:前端和後端開發都能搞定的神奇框架! Django:前端和後端開發都能搞定的神奇框架! Jan 19, 2024 am 08:52 AM

Django:前端和後端開發都能搞定的神奇框架! Django是一個高效、可擴展的網路應用程式框架。它能夠支援多種Web開發模式,包括MVC和MTV,可以輕鬆地開發出高品質的Web應用程式。 Django不僅支援後端開發,還能夠快速建構出前端的介面,透過模板語言,實現靈活的視圖展示。 Django把前端開發和後端開發融合成了一種無縫的整合,讓開發人員不必專門學習

如何在JavaScript中取得HTTP狀態碼的簡單方法 如何在JavaScript中取得HTTP狀態碼的簡單方法 Jan 05, 2024 pm 01:37 PM

JavaScript中的HTTP狀態碼取得方法簡介:在進行前端開發中,我們常常需要處理與後端介面的交互,而HTTP狀態碼就是其中非常重要的一部分。了解並取得HTTP狀態碼有助於我們更好地處理介面傳回的資料。本文將介紹使用JavaScript取得HTTP狀態碼的方法,並提供具體程式碼範例。一、什麼是HTTP狀態碼HTTP狀態碼是指當瀏覽器向伺服器發起請求時,服務

Golang與前端技術結合:探討Golang如何在前端領域發揮作用 Golang與前端技術結合:探討Golang如何在前端領域發揮作用 Mar 19, 2024 pm 06:15 PM

Golang與前端技術結合:探討Golang如何在前端領域發揮作用,需要具體程式碼範例隨著互聯網和行動應用的快速發展,前端技術也愈發重要。而在這個領域中,Golang作為一門強大的後端程式語言,也可以發揮重要作用。本文將探討Golang如何與前端技術結合,以及透過具體的程式碼範例來展示其在前端領域的潛力。 Golang在前端領域的角色作為一門高效、簡潔且易於學習的

See all articles