首页 / 文章 / req-guard-lite:一款以TypeScript为优先的Express简易速率限制器。

req-guard-lite:一款以TypeScript为优先的Express简易速率限制器。

了解轻量级、无依赖的Express速率限制器的工作原理,从内存默认配置到Redis扩展及自定义键生成器。

1291 词

每个 Express 应用最终都会遇到需要实施速率限制的情况。

无论目的是保护登录接口、减少垃圾信息,还是防止意外过度使用,一旦 API 对外公开,限制进入的流量就立刻从可选功能变成了必要要求。

在寻找能满足常见需求的速率限制方案时,我们发现尽管已有许多功能强大的库,但很多项目其实只是希望拥有一个体积小、易于理解且便于定制的工具。

正是这一需求缺口促使我们开发了 req-guard-lite

为何还要另一个速率限制器?

大多数 API 从一开始就不需要完整的企业级安全套件。

通常,人们只需要能够编写类似这样的代码即可:

app.use(rateLimit({
  max: 100,
  windowMs: 15 * 60 * 1000
}));

…然后继续构建应用程序的其余部分。

该模块的设计目标如下:

  • 保持轻量级
  • 易于设置
  • 从一开始就以 TypeScript 为开发基础
  • 便于扩展
  • 既适用于小型项目,也适用于大规模系统

介绍 req-guard-lite

req-guard-lite 是一款精简的 Express 中间件,旨在保护您的 API 免受海量请求的冲击。

默认情况下它完全在内存中运行,但也可以通过接入 Redis 实现向分布式架构的扩展。

它的功能范围被刻意限定——只专注做好一件事:

记录传入的请求,一旦超过设定的限制就拒绝相应客户端。

功能特性

轻量级实现 核心包无任何运行时依赖 可作为 Express 中间件使用 原生支持 TypeScript 可集成 Redis 支持自定义存储后端 支持自定义键生成器

快速入门

将其作为 Express 的配套组件进行安装。

npm install req-guard-lite express

接下来,将其接入您的应用中。

import express from 'express';
import { rateLimit } from 'req-guard-lite';

const app = express();

const limiter = rateLimit({
    windowMs: 15 * 60 * 1000,
    max: 100,
    message: 'Too many requests, please try again later.'
});

app.use(limiter);

app.get('/', (req, res) => {
    res.send('Hello World!');
});

app.listen(3000);

这就是全部的设置流程。

现在,您的 API 会阻止任何客户端在15分钟内发送超过100次请求。

默认内存存储

开箱即用,请求计数器存储在内存中。

实际意义如下:

  • 无需 Redis
  • 无需数据库
  • 无需额外配置
  • 非常适合本地开发
  • 单服务器生产环境中的理想选择

对于大多数应用而言,这已经是最为必要的限流方式了。

利用 Redis 实现扩展

当应用需要部署在多台服务器或容器上运行时,这些实例就需要一个共享的请求计数视图。

这就是 Redis 在此发挥的作用。

import Redis from "ioredis";
import { createRedisStore } from "req-guard-lite/redis";

const redis = new Redis();
const limiter = rateLimit({
    max: 100,
    windowMs: 15 * 60 * 1000,
    store: createRedisStore(redis, {
        max: 100,
        windowMs: 15 * 60 * 1000
    })
});

通过这种方式,每个服务器实例都会读取和写入相同的计数器,因此无论哪个节点处理请求,限流规则都能保持一致。

自定义键生成器

按 IP 地址进行限流并不总是最佳方案。

在某些情况下,你可能更希望根据以下内容设置限流:

  • 用户 ID
  • API 密钥
  • 租户标识符
  • 组织单位
  • JWT 主体声明
  • 或任何符合你业务模型的其他标识符

为支持这一点,req-guard-lite允许你提供自己的密钥生成函数。

const limiter = rateLimit({
    max: 100,
    keyGenerator: (req) =>
        req.headers["x-api-key"] as string
});

或者,以已登录用户作为密钥:

const limiter = rateLimit({
    max: 50,
    keyGenerator: (req) =>
        (req as any).user.id
});

该中间件本身并不关心密钥代表什么——它只是根据你的函数返回的任何标识符来计数。

自行实现存储机制

从一开始,可扩展性就是核心要求之一。

req-guard-lite并未强制你使用Redis,而是提供了一个简单的RateLimitStore接口。如果你的基础设施已经依赖:

  • PostgreSQL
  • DynamoDB
  • Memcached
  • MongoDB
  • SQLite
  • 其他自定义缓存层

你只需实现该接口即可将其集成进来。

class MyStore implements RateLimitStore {
    consume(key: string) {
        // your implementation
    }
}

这种设计使得该包能够适配您正在使用的几乎所有后端系统。

一个重要的生产环境建议

如果您的应用运行在以下设备之后:

  • Nginx
  • AWS负载均衡器
  • Heroku
  • Cloudflare
  • 任何反向代理服务器

请务必正确配置Express:

app.set("trust proxy", 1);

如果跳过这一步,Express往往会将每个传入的请求都视为来自代理服务器本身,这意味着所有用户最终都会共享同一个速率限制阈值。这只是一个简单的修改,却能避免许多团队在生产环境中遇到的麻烦。

工作原理

其内部流程被刻意设计得极为简单:

  1. 有请求传入。
  2. 中间件会为该请求生成一个键值(默认为客户端IP地址)。
  3. 当前使用的存储机制会递增与该键值关联的计数器。
  • 一旦计数器超过预设阈值,中间件会返回 HTTP 429 Too Many Requests 响应。
  • 如果未达到限制,请求将原样通过。
  • 由于该存储系统支持插件化,无论背后使用的是内存、Redis还是自定义实现,都遵循相同的处理流程。

    为何选择 TypeScript?

    整个库均用 TypeScript 编写,由此带来以下优势:

    • 全程严格的类型控制
    • 更完善的编辑器自动补全功能
    • 更简单的长期维护
    • 更难被误用的 API 接口

    使用 TypeScript 的用户可以直接获得完整的类型定义,无需额外安装 @types 包。

    发展路线图

    开发工作仍在持续,已有若干新功能正在规划中。

    v0.4.0

    • 支持标准的速率限制响应头
    X-RateLimit-Limit
    X-RateLimit-Remaining
    X-RateLimit-Reset
    

    这些响应头能让客户端应用程序了解在达到限制之前还剩多少请求。

    v0.5.0

    当超过限制时会触发可配置的钩子函数,适用于以下场景:

    • 日志记录
    • 指标收集
    • 警报发送
    • 数据分析
    • 将数据发送到外部监控工具

    为何选择开源

    这个项目的诞生并非因为现有库存在不足——Node 生态系统中已经有了几款出色的限流解决方案。req-guard-lite的出现是因为其目标是打造这样一个包:

    • 简洁到可以一次性读懂
    • 易于扩展
    • 以 TypeScript 为设计基础
    • 没有不必要的复杂性
    • 足够灵活,能随着实际生产需求进行扩展

    开发这个项目也是一次宝贵的实践机会,让我学会了如何打包发布、设计API、编写测试代码、与Redis集成,以及创建便于其他开发者使用的抽象层。

    结语

    将项目开源是提升工程技能最有效的方法之一。一旦其他开发者能够安装、使用并为你贡献代码,你就不得不考虑超出自身直接需求之外的问题——文档编写、API设计、测试、版本控制以及向后兼容性都成了你必须解决的现实约束。

    req-guard-lite最初只是为满足个人需求而开发的一个小型中间件,但希望它能发展成一款对其他Express开发者来说实用、轻量且可扩展的限流工具。欢迎任何反馈、功能建议及代码贡献。

    相关阅读