⚙️ Next.js 接口限流与审计全攻略 —— 用 @upstash/ratelimit 打造优雅“闸门”

🌊 为什么要"限流"?

想象一个场景:你辛辛苦苦搭建的 Next.js API 服务,正沐浴在阳光下稳定运行,忽然来了一个过分勤劳的客户端用户(或机器人 🤖),开始毫无节制地请求接口,疯狂到让 CPU 开始思考人生。

结果自然是:

💥「服务崩溃 → 用户暴躁 → 老板追杀」

于是我们需要"限流机制"(Rate Limiting)。

限流的本质,就是在 单位时间内限制某个用户或 IP 的请求次数,从而保持服务稳定。例如:

指标 意义
10 req / 10 s 每 10 秒最多处理 10 个请求
100 req / min 每分钟处理 100 个请求
429 状态码 拒绝请求并提示"停一下!"

🧩 Upstash 与 Redis ------ 天作之合

我们不想自己去维护复杂的 Redis 集群来追踪请求计数,于是 Upstash 这个小精灵出现了:

  • ☁️ 无服务器 Redis(Serverless Redis)
  • 💸 按调用计费,不用担心多一分钱的浪费
  • ⚡️ 延迟低,速度快
  • 🔐 免费额度够个人项目用

@upstash/ratelimit 就是它的魔法棒,让限流在 Next.js 中轻松实现。


🚀 开始动手:Next.js + @upstash/ratelimit

下面我们构造一个限流且带审计日志的 API。

1️⃣ 安装依赖

bash 复制代码
npm install @upstash/ratelimit @upstash/redis

2️⃣ 创建 Redis 客户端

/lib/redis.js

arduino 复制代码
import { Redis } from "@upstash/redis";

export const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL,
  token: process.env.UPSTASH_REDIS_REST_TOKEN,
});

🔑 安全提示: 环境变量千万别放到 GitHub 上,除非你想给别人白送额度。

3️⃣ 初始化 RateLimiter

/lib/ratelimit.js

javascript 复制代码
import { Ratelimit } from "@upstash/ratelimit";
import { redis } from "./redis";

export const ratelimit = new Ratelimit({
  redis,
  limiter: Ratelimit.slidingWindow(5, "10 s"), // 每10秒最多允许5次请求
  analytics: true, // 启用分析数据
  prefix: "ratelimit:api",
});

🔍 审计日志:记录谁在"频繁敲门"

当请求超限时,我们顺带写入日志。

日志可以简单保存在 Redis,也可以后续接入到像 Datadog、OpenTelemetry 等监控系统。

/pages/api/hello.js

javascript 复制代码
import { ratelimit } from "../../lib/ratelimit";
import { redis } from "../../lib/redis";

export default async function handler(req, res) {
  const ip = req.headers["x-real-ip"] || req.socket.remoteAddress || "unknown";

  const { success, limit, reset, remaining } = await ratelimit.limit(ip);

  if (!success) {
    await redis.rpush("audit:rate_limit_log", {
      ip,
      time: new Date().toISOString(),
      path: req.url,
    });

    return res.status(429).json({
      message: "⛔ 太快啦,稍等一下再试!",
      limit,
      reset,
      remaining,
    });
  }

  res.status(200).json({ message: `✅ 欢迎,来自 ${ip} 的合格请求!` });
}

📈 小试牛刀:查看日志

只要登录 Redis 查看我们写入的日志:

ini 复制代码
const logs = await redis.lrange("audit:rate_limit_log", 0, -1);
console.log("🚨 限流日志记录:", logs);

输出示例:

lua 复制代码
[
  { ip: '203.0.113.1', time: '2025-10-31T06:00:00Z', path: '/api/hello' },
  { ip: '203.0.113.1', time: '2025-10-31T06:00:02Z', path: '/api/hello' },
  ...
]

📜 小贴士:你也可以用 Cloudflare KV、Supabase 或 PostgreSQL 来保存日志,用于更强大的审计分析。


🧠 一点底层思考:Rate Limit 的本质

限流算法背后其实就像"水桶原理"一样。常见的策略有:

  • 🪣 固定窗口(Fixed Window) :简单粗暴,每个时间窗限固定次数。
  • 滑动窗口(Sliding Window) :更平滑,统计窗口"滑动"过去一段时间请求。
  • 💧 令牌桶(Token Bucket) :每次请求取一个"令牌",定期补充。
  • 💦 漏桶(Leaky Bucket) :请求流入"桶",系统按固定速率漏出处理。

@upstash/ratelimit 默认提供了"滑动窗口",兼顾性能与公平性。


🖼️ 可视化(脑内小剧场)

下面是一幅简单的比喻图:

arduino 复制代码
┌──────────┐       请求 x5 次/10秒
│ Client 🌍│ ─────┐
└──────────┘      │
                   ▼
             ┌──────────┐
             │ Ratelimit │ ------ "5次够了!去喝杯茶☕"
             └──────────┘
                   ▼
             ┌──────────┐
             │ Redis 🧠 │ ← 记录日志 & 限流计数
             └──────────┘

🧾 总结

项目 内容
功能 限制接口调用速率、防止滥用
@upstash/ratelimit, @upstash/redis
审计 Redis 保存请求日志
应用场景 API 接口、Webhooks、防刷票系统
优点 简洁、轻量、Serverless 友好

🎁 拓展玩法(进阶食谱)

  • 多维度限流:不仅按 IP,还可以按用户 ID、API key、Referer 等。
  • 图表可视化审计:用 Next.js/Chart.js 展示限流日志的趋势。
  • 智能警告系统:超过阈值时触发 Slack/Email 通知管理员。
  • 动态限流:高峰期更严,闲时更松。
相关推荐
Mintopia6 小时前
🌐 实时翻译 + AIGC:Web跨语言内容生成的技术闭环
前端·javascript·aigc
Cache技术分享6 小时前
225. Java 集合 - List接口 —— 记住顺序的集合
前端·后端
前端开发爱好者6 小时前
Vite+ 获得 1250万美元的 A 轮融资,生态加速!
前端·javascript
Larcher6 小时前
JS 变量声明避坑指南:彻底搞懂 var/let/const 的 3 大核心区别与最佳实践
前端·javascript·node.js
拖拉斯旋风6 小时前
0基础学习Openai之:通过Prompt生成你心中的那幅画🎨
javascript·openai
爱抽烟的大liu6 小时前
iOS 进阶6-Voip通信
前端
boboj16 小时前
Vue过渡至React的基础理解
前端·react.js
Zyx20076 小时前
用 CSS 演绎浪漫:从零构建“亲吻动画”全流程解析
前端·css
llq_3506 小时前
在 antd Table 中实现多行省略和 Tooltip
前端