如何在 Ubuntu 上使用 Node.js 和 TypeScript 构建API速率限制器教程

简介

在本教程中,你将学习如何使用 Node.js 和 TypeScript 语言构建一个速率限制器。

速率限制对于防止滥用、保护你的 API 以及管理资源至关重要。我们将使用 Node.js 构建一个生产级的速率限制器,并将其部署在现代应用程序平台上。该速率限制器将使用 Redis 来进行高效的状态管理,并集成到一个示例 API 应用程序中。

速率限制的关键概念

  • 速率限制: 限制用户或客户端在特定时间窗口内可以发出的请求数量。
  • 令牌桶算法: 一种流行的速率限制实现算法,它定期授予令牌,只有在有令牌可用时才允许请求。
  • Redis: 一种高性能的内存数据存储,用于管理分布式系统(如 API)的状态。

本教程的目标是手把手教你如何在 Linux 服务器上安装并配置一个使用 Node.js 和 TypeScript 构建的速率限制器。

准备工作

服务器准备

必要前提:

  • 一个充满求知欲的大脑。
  • 一台 Linux 服务器(推荐腾讯云、阿里云或雨云等)。

我将以 雨云 为例,带大家创建一台自己的云服务器,以便学习本篇文章的内容。

注册链接: https://rainyun.ivwv.site

创建雨云服务器

以下步骤仅供参考,请根据实际需求选择配置。

  • 点击 云产品云服务器立即购买
  • 选择距离你较近的区域,以保证低延迟。
  • 按照自己需求选择配置,选择Ubuntu 22.04 版本,按照自己需求是否预装Docker。
  • 最后按照提示进行购买。
  • 购买后等待机器部署完毕,点击刚刚创建好的服务器,进入管理面板,找到远程连接相关信息。
  • 我们使用 PowerShell 进行 SSH 远程连接到服务器,Win+R 打开运行窗口,输入 powershell 后点击确定。
  • 输入 ssh root@你的服务器IP 例如 ssh root@154.9.227.239 回车后,首次需要输入 yes,再次回车后即可登录服务器。
  • 到此为止,我们的云服务器就远程连接上了。

安装和配置步骤

第一步:创建一个 Node.js 应用程序

初始化项目

bash 复制代码
mkdir rate-limiter-app
cd rate-limiter-app
npm init -y

安装依赖

bash 复制代码
npm install express redis dotenv

安装开发工具

bash 复制代码
npm install --save-dev typescript @types/node ts-node @types/express

第二步:设置 Redis 用于速率限制

创建一个 redisClient.ts 文件来处理 Redis 交互:

bash 复制代码
nano redisClient.ts

添加以下代码:

js 复制代码
import { createClient, RedisClientType } from 'redis';
import dotenv from 'dotenv';

// Load environment variables from .env file
dotenv.config();

class RedisClient {
  private static instance: RedisClientType | null = null;

  /**
   * Initialize Redis client or return an existing instance.
   */
  public static getInstance(): RedisClientType {
    if (!RedisClient.instance) {
      const redisUrl = process.env.REDIS_URL || 'redis://127.0.0.1:6379';

      try {
        // Create Redis client
        RedisClient.instance = createClient({
          url: redisUrl,
        });

        // Add error handling
        RedisClient.instance.on('error', (err) => {
          console.error(`Redis Client Error: ${err.message}`);
        });

        // Connect to Redis
        RedisClient.instance.connect().catch((err) => {
          console.error(`Failed to connect to Redis: ${err.message}`);
        });

        console.info(`Connected to Redis at ${redisUrl}`);
      } catch (err) {
        console.error('Error initializing Redis client:', err);
        throw err;
      }
    }

    return RedisClient.instance;
  }

  /**
   * Disconnect Redis client (useful during app shutdown).
   */
  public static async disconnect(): Promise<void> {
    if (RedisClient.instance) {
      await RedisClient.instance.quit();
      RedisClient.instance = null;
      console.info('Disconnected from Redis.');
    }
  }
}

export default RedisClient;

此设置连接到 Redis 实例,并确保客户端在整个应用程序中可用。

第三步:实现速率限制器中间件

创建一个 rateLimiter.ts 文件:

bash 复制代码
nano rateLimiter.ts

添加以下代码:

js 复制代码
import { Request, Response, NextFunction } from 'express';
import { createClient, RedisClientType } from 'redis';
import dotenv from 'dotenv';

// Load environment variables
dotenv.config();

// Redis client setup
const redisClient: RedisClientType = createClient({
  url: process.env.REDIS_URL || 'redis://127.0.0.1:6379',
});

// Connect Redis client
redisClient.connect().catch((err) => {
  console.error('Error connecting to Redis:', err);
});

interface RateLimiterOptions {
  windowMs: number; // Time window in milliseconds
  maxRequests: number; // Maximum allowed requests in the time window
}

export const rateLimiter = (options: RateLimiterOptions) => {
  const { windowMs, maxRequests } = options;

  return async (req: Request, res: Response, next: NextFunction) => {
    try {
      const key = `rate-limit:${req.ip}`; // Unique key per user/IP
      const currentCount = await redisClient.incr(key);

      if (currentCount === 1) {
        // Set expiry time for the key
        await redisClient.expire(key, Math.ceil(windowMs / 1000));
      }

      if (currentCount > maxRequests) {
        const ttl = await redisClient.ttl(key); // Time until key expires
        return res.status(429).json({
          message: 'Too many requests. Please try again later.',
          retryAfter: ttl,
        });
      }

      next(); // Allow request to proceed
    } catch (error) {
      console.error('Rate limiter error:', error);
      res.status(500).json({ message: 'Internal Server Error' });
    }
  };
};

第四步:创建带速率限制的 API

创建一个 app.ts 文件:

bash 复制代码
nano app.ts

添加以下代码:

js 复制代码
import express, { Request, Response } from 'express';
import { rateLimiter } from './rateLimiter';

const app = express();
const PORT = process.env.PORT || 3000;

// Apply rate limiter middleware
app.use(
  rateLimiter({
    windowMs: 60 * 1000, // 1 minute window
    maxRequests: 10, // Limit each IP to 10 requests per windowMs
  })
);

// Example route
app.get('/', (req: Request, res: Response) => {
  res.send('Welcome! You are not rate-limited yet.');
});

// Start the server
app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

测试应用程序

编译 TypeScript:

bash 复制代码
npx tsc

运行服务器:

bash 复制代码
node dist/app.ts

测试速率限制

使用 Postman 或 curl 等工具:

bash 复制代码
curl http://localhost:3000
  • 在 60 秒内发出超过 10 个请求来触发速率限制器。
  • 观察 429 Too Many Requests 响应。

生产级注意事项

  • 使用安全的 Redis 配置: 确保启用身份验证,并且该实例不会公开。
  • 分布式速率限制: 如果应用程序水平扩展,则使用集中的 Redis 实例。
  • 日志记录和监控: 集成 Winston 等工具进行日志记录,并集成 Prometheus 进行监控。

结尾

本教程演示了如何使用 Node.js 和 Redis 构建一个健壮的、生产级的速率限制器,以及在现代应用程序平台上部署的步骤。通过遵循这些实践,你可以有效地管理 API 使用并保护你的资源免受滥用。

推广链接:

相关推荐
winstongit10 分钟前
SSH多秘钥管理
运维·ssh
ueanaIU潇潇子44 分钟前
Linux系统安装es详细教程
linux·运维·elasticsearch
关关钧1 小时前
【Linux】信号处理
linux·运维·信号处理
一个单纯的少年1 小时前
HTTP STATUS CODE详情,HTTP状态码大全列表
服务器·前端·网络·后端·网络协议·http·产品运营
Cikiss2 小时前
Tomcat解析
java·服务器·后端·servlet·tomcat
Heris992 小时前
linux shell脚本 【分支结构case...in 、循环结构、函数】内附练习
linux·服务器·ubuntu·vim
007php0072 小时前
服务器systemctl命令使用与go项目zero框架中实战
java·运维·服务器·网络·golang·php·ai编程
龙少95432 小时前
【服务器常见网络攻击】
运维·服务器
明 庭3 小时前
在 Ubuntu 下通过 Docker 部署 MySQL 服务器
服务器·ubuntu·docker
tryCbest3 小时前
Django项目部署到服务器
服务器·python·django