最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

nestjs使用redis實現(xiàn)ip限流的步驟詳解

 更新時間:2025年01月15日 08:29:44   作者:程序員零塔  
如果使用nestjs開發(fā)接口并部署之后,我們通常需要考慮到接口是否會被惡意盜刷消耗過多的資源,一個簡單的方式就是限制在單位時間內(nèi)的訪問次數(shù),所以本文給大家介紹了nestjs使用redis實現(xiàn)ip限流的步驟,需要的朋友可以參考下

導讀

如果使用nestjs開發(fā)接口并部署之后,我們通常需要考慮到接口是否會被惡意盜刷消耗過多的資源,一個簡單的方式就是限制在單位時間內(nèi)的訪問次數(shù)。

本文使用的庫包版本如下:

庫名版本號
@nestjs/core10.0.0
@nestjs/common10.0.0
@nestjs/schedule4.1.2
ioredis5.4.2

本文的主要工作環(huán)境基于Macbook Pro M1 MacOS 14.6.1。

新建nestjs 項目

nest new nestjs-with-ip-limit -g

nestjs中的守衛(wèi)Guard

nestjs 提供了一種可以是否攔截請求的方式,守衛(wèi)(Guard),我們可以通過實現(xiàn)CanActive接口來完成,詳細解釋參考官方鏈接。

自定義的一個ip.guard.ts文件,用于最終實現(xiàn)我們的ip請求攔截。

//ip.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
?
@Injectable()
export class IpGuard implements CanActivate {
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const request = context.switchToHttp().getRequest();
    console.log(request.headers['origin'], request.headers);
    return request.headers['text'] != 'zoo' ? false : true;
  }
}

在示例中,我們增加當請求頭沒有text=zoo就攔截的邏輯,并直接在瀏覽器控制臺中使用fetch測試:

fetch('http://localhost:3000', {
  headers: {
    text: 'zoo',
  },
})
  .then((resp) => resp.text())
  .then(console.log)
  .catch(console.error);

可以看到,一旦守衛(wèi)中返回了false,請求將報403請求錯誤。

Guard中獲取IP

現(xiàn)在的問題就是如何在實現(xiàn)的IpGuard中獲取ip地址,可以通過context.switchToHttp().getRequest()獲取請求對象來提取。

const request = context.switchToHttp().getRequest();
const ip = request.headers['x-forwarded-for'] || request.headers['x-real-ip'] || request.socket.remoteAddress || request.ip;

x-forwarded-forx-real-ip的依據(jù)主要是我們很多網(wǎng)站可能使用代理的方式運行,尤其是nginx代理,如下所示。

location ^~ /api {
    rewrite ^/api(.*) $1 break; # 重寫規(guī)則,將/api之后的路徑提取出來并去掉/api前綴
    proxy_pass http://127.0.0.1:6689; 
    proxy_set_header Host $host; 
    proxy_set_header X-Real-IP $remote_addr; // 設(shè)置 X-Real-IP 頭為客戶端的真實 IP 地址。這對于后端服務識別客戶端 IP 地址非常重要,特別是在請求經(jīng)過多個代理的情況下
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; // 設(shè)置 X-Forwarded-For 頭為通過 proxy_add_x_forwarded_for 指令添加的信息。此頭通常用于跟蹤客戶端 IP 地址以及任何之前的代理 IP 地址
    proxy_set_header REMOTE-HOST $remote_addr; 
    proxy_set_header Upgrade $http_upgrade; 
    proxy_set_header Connection "upgrade"; 
    proxy_set_header X-Forwarded-Proto $scheme; 
    proxy_http_version 1.1; 
    add_header X-Cache $upstream_cache_status; 
    add_header Cache-Control no-cache; 
    proxy_ssl_server_name off; 
}

ip存儲

提取到ip地址后我們需要將其和請求數(shù)保存,并同時記錄訪問數(shù)(每次增加1),且在某段時間后清除,為此,我們需要引入redis。

npm i ioreds -s

為了后續(xù)更方便的使用,把redis封裝為一個自建的module

nest g module redis --no-spec

新建src/redis/redis.service.ts

import { Injectable } from '@nestjs/common';
?
import Client, { type RedisOptions } from 'ioredis';
?
@Injectable()
export class RedisService extends Client {
  constructor(options: RedisOptions) {
    super(options);
  }
}

redis.module.ts中加入代碼

import { Module } from '@nestjs/common';
import { RedisOptions } from 'ioredis';
import { RedisService } from './redis.service';

@Module({})
export class RedisModule {
  static forRoot(optionts: RedisOptions) {
    return {
      module: RedisModule,
      providers: [
        {
          provide: 'REDIS_OPTIONS',
          useValue: optionts,
        },
        {
          provide: RedisService,
          useFactory: (options: RedisOptions) => {
            return new RedisService(options);
          },
          inject: ['REDIS_OPTIONS'],
        },
      ],
      exports: [RedisService],
    };
  }
}

在app.module.ts中使用

新建一個redis容器:

隨后改造ip.guard.ts文件

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { RedisService } from './redis/redis.service';

@Injectable()
export class IpGuard implements CanActivate {
  constructor(private redisService: RedisService) {}
  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const ip =
      request.headers['x-forwarded-for'] ||
      request.headers['x-real-ip'] ||
      request.socket.remoteAddress ||
      request.ip;
    const redis_key = 'limit_ip_' + ip;
    const data = await this.redisService.get(redis_key);
    const count = data ? parseInt(data) : 0;
    if (count >= 5) {
      return false;
    }
    await this.redisService.set(
      redis_key,
      data ? parseInt(data) + 1 : 1,
      'EX',
      60,
    );
    return true;
  }
}

每次接口訪問時,都會先從redis里讀取對應ip的訪問次數(shù),如果達到五次后,就返回false禁止接口應答,否則通過,并且該限制在一分鐘內(nèi)有效。

在瀏覽器請求http://localhost:3000,刷新四次后,顯示如下。::1是由于本地開發(fā)的緣故,如果有服務器可以在服務器上啟動服務,本地測試。

部署到服務器后顯示:

補充

現(xiàn)在經(jīng)常使用的一些AI工具,其免費計劃每天都只有很少的額度,其也可以基于redis實現(xiàn)限流,不過是根據(jù)用戶id來設(shè)置key值。除此之外,其每天到零點時還可以恢復額度。為此,可以在nestjs使用定時器在零點時刪除所有的redis的ke y。

安裝相關(guān)依賴

npm install @nestjs/schedule

注冊定時任務模塊

imports: [
    RedisModule.forRoot({
      host: 'localhost',
      port: 6378,
      db: 0,
    }),
    ScheduleModule.forRoot(),
  ],

app.service.ts加入代碼

import { Injectable } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { RedisService } from './redis/redis.service';

@Injectable()
export class AppService {
  constructor(private readonly redisService: RedisService) {}
  getHello(): string {
    return 'Hello World!';
  }

  @Cron(CronExpression.EVERY_DAY_AT_1AM)
  async handleCron() {
    console.log('Called when the current time is 1AM');
    //刪除所有的redis keys: limit_ip_*
    await this.redisService.del('limit_ip_*');
  }
}

此外,也可以在定時任務中將相關(guān)的限流ip的計數(shù)同步到MySQL,讓相關(guān)邏輯更穩(wěn)檔一些。

以上就是nestjs使用redis實現(xiàn)ip限流的步驟詳解的詳細內(nèi)容,更多關(guān)于nestjs redis實現(xiàn)ip限流的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Redis中的zset類型詳解

    Redis中的zset類型詳解

    有序集合zset保留了set集合不能有重復成員的特點,但與set集合不同的是,zset的每個member都有一個唯一的浮點數(shù)類型的分數(shù)score與之關(guān)聯(lián),這篇文章主要介紹了Redis的zset類型,需要的朋友可以參考下
    2023-08-08
  • 詳解Redis Stream做消息隊列

    詳解Redis Stream做消息隊列

    這篇文章主要介紹了詳解Redis Stream做消息隊列,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • Redis的過期策略以及內(nèi)存淘汰機制詳解

    Redis的過期策略以及內(nèi)存淘汰機制詳解

    這篇文章主要介紹了Redis的過期策略以及內(nèi)存淘汰機制,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Redis8.0.3編譯化安裝的實現(xiàn)

    Redis8.0.3編譯化安裝的實現(xiàn)

    本文主要介紹了Redis8.0.3編譯化安裝的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-08-08
  • sentinel支持的redis高可用集群配置詳解

    sentinel支持的redis高可用集群配置詳解

    這篇文章主要為大家介紹了sentinel支持的redis高可用集群配置詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-04-04
  • 在ssm項目中使用redis緩存查詢數(shù)據(jù)的方法

    在ssm項目中使用redis緩存查詢數(shù)據(jù)的方法

    本文主要簡單的使用Java代碼進行redis緩存,即在查詢的時候先在service層從redis緩存中獲取數(shù)據(jù)。如果大家對在ssm項目中使用redis緩存查詢數(shù)據(jù)的相關(guān)知識感興趣的朋友跟隨腳本之家小編一起看看吧
    2018-03-03
  • Redis的哨兵模式工作流程及原理詳解

    Redis的哨兵模式工作流程及原理詳解

    Redis哨兵模式是高可用解決方案,通過監(jiān)控、故障檢測、自動故障轉(zhuǎn)移和配置更新保障服務連續(xù),本文給大家介紹Redis的哨兵模式工作流程及原理詳解,感興趣的朋友一起看看吧
    2025-08-08
  • redis中的常用5大數(shù)據(jù)類型

    redis中的常用5大數(shù)據(jù)類型

    這篇文章主要介紹了redis中的常用5大數(shù)據(jù)類型,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Redis解決秒殺微服務搶購代金券超賣和同一個用戶多次搶購

    Redis解決秒殺微服務搶購代金券超賣和同一個用戶多次搶購

    本文介紹了如何用Redis和Redisson分布式鎖解決秒殺中的超賣和同一用戶重復搶購問題,通過Lua腳本保證操作原子性,最終實現(xiàn)庫存和訂單的準確控制,感興趣的可以了解一下
    2025-09-09
  • Redis批量生成數(shù)據(jù)的實現(xiàn)

    Redis批量生成數(shù)據(jù)的實現(xiàn)

    本文主要介紹了Redis批量生成數(shù)據(jù)的實現(xiàn),主要介紹了兩種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06

最新評論

宁城县| 会东县| 阜康市| 隆子县| 乌审旗| 辽阳市| 夏邑县| 陇川县| 通州区| 手游| 东丰县| 奉新县| 寿宁县| 绥芬河市| 金坛市| 商水县| 通化市| 五原县| 萨嘎县| 社旗县| 驻马店市| 美姑县| 鄄城县| 桂阳县| 夏邑县| 介休市| 德江县| 延吉市| 新龙县| 武川县| 舞阳县| 旌德县| 泸定县| 沙湾县| 四川省| 宁蒗| 西充县| 长治市| 台州市| 汝城县| 华安县|