Taocarts接口限流实操:基于Redis实现API防刷与流量管控

跨境Taocarts站点面向全球公网用户,极易遭遇恶意刷接口、爬虫高频请求、CC攻击等问题,高频无效请求会耗尽服务器带宽、数据库资源,导致正常用户接口卡顿、超时。原生系统无任何限流机制,接口完全裸奔,安全性极差。普通的内存限流仅支持单机部署,无法适配Taocarts集群多节点架构,存在限流失效漏洞。本文将基于Redis实现分布式接口限流,支持IP、用户账号双维度限流,支持自定义限流频次,适配集群部署,附带完整可落地代码。

分布式限流核心原理是借助Redis的过期键+自增计数器特性,实现全节点流量统一统计,区别于单机内存限流,集群环境下数据完全互通,不会出现限流阈值失效问题。我们将实现注解式限流,支持接口灵活配置秒级、分钟级访问频次,适配登录、下单、爬虫、查询等不同接口的防护需求。

首先封装Redis限流工具类,实现请求计数、过期设置、频次判断核心逻辑:

typescript 复制代码
// src/common/utils/redis-limit.util.ts
import { InjectRedis } from '@nestjs/redis';
import { Redis } from 'ioredis';
import { Injectable } from '@nestjs/common';

@Injectable()
export class RedisLimitUtil {
  constructor(@InjectRedis() private redis: Redis) {}

  /**
   * 分布式限流
   * @param key 限流唯一key
   * @param limit 最大请求次数
   * @param second 过期时间(秒)
   * @returns true=限流通过 false=触发限流
   */
  async limit(key: string, limit: number, second: number): Promise<boolean> {
    // 原子自增
    const count = await this.redis.incr(key);
    // 首次请求设置过期时间
    if (count === 1) {
      await this.redis.expire(key, second);
    }
    // 判断是否超过限制频次
    return count <= limit;
  }
}

自定义限流注解,实现接口灵活配置,无需重复编写限流逻辑:

typescript 复制代码
// src/common/decorator/rate-limit.decorator.ts
import { SetMetadata } from '@nestjs/common';

export interface RateLimitOption {
  limit: number;    // 限制次数
  second: number;   // 限制时间
  type: 'ip' | 'user'; // 限流维度
}

export const RateLimit = (options: RateLimitOption) => SetMetadata('rateLimit', options);

编写限流守卫,拦截所有带注解的接口,自动校验请求频次,IP限流适配匿名访问接口,用户限流适配登录后接口:

typescript 复制代码
// src/common/guard/rate-limit.guard.ts
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { RateLimitOption } from '../decorator/rate-limit.decorator';
import { RedisLimitUtil } from '../utils/redis-limit.util';
import { BusinessException, ErrorCode } from '../exception/business.exception';

@Injectable()
export class RateLimitGuard implements CanActivate {
  constructor(private reflector: Reflector, private redisLimit: RedisLimitUtil) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const options = this.reflector.get<RateLimitOption>('rateLimit', context.getHandler());
    if (!options) return true;

    const req = context.switchToHttp().getRequest();
    // 生成唯一限流KEY
    let key = `rate_limit:${context.getClass().name}:${context.getHandler().name}`;
    if (options.type === 'ip') {
      key += `:ip:${req.ip}`;
    } else {
      key += `:user:${req.user?.userId}`;
    }

    // 校验限流
    const pass = await this.redisLimit.limit(key, options.limit, options.second);
    if (!pass) {
      throw new BusinessException(ErrorCode.COMMON_ERROR, '请求过于频繁,请稍后再试');
    }
    return true;
  }
}

接口使用示例,给商品爬虫、登录、查询接口添加限流防护:

typescript 复制代码
@Controller('goods')
export class GoodsController {
  // IP限流:10秒最多访问5次,防爬虫刷取商品接口
  @Get('list')
  @UseGuards(RateLimitGuard)
  @RateLimit({ limit: 5, second: 10, type: 'ip' })
  async getGoodsList() {
    return await this.goodsService.getList();
  }

  // 用户限流:1分钟最多下单3次,防恶意刷单
  @Post('order/create')
  @UseGuards(RateLimitGuard)
  @RateLimit({ limit: 3, second: 60, type: 'user' })
  async createOrder() {
    // 下单逻辑
  }
}

该限流方案完美适配Taocarts集群部署架构,所有服务器节点共享Redis限流数据,无单点失效问题。可针对不同接口精细化配置防护规则,有效拦截恶意刷接口、爬虫高频抓取、恶意刷单等行为,保护服务器与数据库资源,大幅提升跨境站点抗攻击能力,是商用跨境系统必备的安全防护方案。

相关推荐
这个DBA有点耶22 分钟前
AI写的SQL跑崩了生产库,这锅谁背?
数据库·人工智能·程序员
镜舟科技1 小时前
Databricks 再提 LTAP,AI 时代的数据底座为何重回大一统叙事?
数据库·架构·agent
Databend2 小时前
从湖仓升级为 Agent 时代的数据控制面,Snowflake 和 Databricks 有哪些布局
大数据·数据库·agent
ClouGence5 小时前
SQL Server CDC 能放到 Always On 备库读吗?一文讲透原理与实践
数据库·sql server
先吃饱再说1 天前
存储的进化:从 MySQL 到浏览器缓存,数据到底住在哪?
数据库
Nturmoils1 天前
字段太多看不全,ksql 的展开模式和输出控制怎么用
数据库·后端
Databend1 天前
Agent 轨迹分析与归因的数据工程实践
大数据·数据库·agent
这个DBA有点耶1 天前
SQL改写进阶:标量子查询的“隐形代价”与消除实战
数据库·mysql·架构
smallyoung1 天前
数据库乐观锁深度解析:MySQL、PostgreSQL 实战 + Spring Boot 集成指南
数据库·mysql·postgresql
parade岁月1 天前
MySQL JOIN解析:朴实无华但食之有味
数据库·后端