You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS中间件中Rate Limit限流失效问题求助

问题原因与解决方案

核心问题

你的限流逻辑在API路由正常,但Middleware中计数始终为1的原因是:

  • API路由运行在Node.js环境,模块级的limiter = rateLimit()只会初始化一次,rateLimit内部的LRU缓存是全局单例,能在请求间保留计数。
  • Middleware运行在Edge Runtime环境,由于Edge函数的无状态特性,每次请求可能会重新执行模块代码,导致rateLimit()被反复调用,每次都创建全新的LRU缓存,计数自然无法累加。

修复方案

把LRU缓存实例提升到模块顶级作用域,确保整个应用生命周期内只有一个缓存实例,而非每次调用rateLimit()都新建。

修改后的src/helpers/rateLimit.js:

import LRU from 'lru-cache'

// 全局唯一的LRU缓存实例(模块顶级作用域)
const tokenCache = new LRU({
  max: 500, // 每秒最多500个用户
  ttl: 1 * 60000, // 缓存有效期1分钟
})

const limit = 3

export default function rateLimit() {
  return {
    // 传入req,支持按IP/用户限流(更合理的方案)
    check: (res, req) =>
      new Promise((resolve, reject) => {
        // 用请求IP作为缓存key,替代固定token
        const token = req?.ip || 'global-limit'
        const tokenCount = tokenCache.get(token) || [0]
        
        if (tokenCount[0] === 0) {
          tokenCache.set(token, tokenCount)
        }

        tokenCount[0] += 1
        const currentUsage = tokenCount[0]
        const isRateLimited = currentUsage >= limit

        res.headers.set('X-RateLimit-Limit', limit)
        res.headers.set('X-RateLimit-Remaining', isRateLimited ? 0 : limit - currentUsage)

        console.log(tokenCache.get(token))

        isRateLimited ? reject() : resolve()
      }),
  }
}

对应的Middleware修改(传入req参数):

import { NextResponse } from 'next/server'
import rateLimit from '@/helpers/rateLimit'

const limiter = rateLimit()

export async function middleware(req) {
  const response = NextResponse.next()

  try {
    await limiter.check(response, req) // 传入req用于获取IP
  } catch (error) {
    console.log(error)
    return NextResponse.json({ error: 'Rate limit exceeded' }, { status: 429 })
  }

  return response // 必须返回response,否则头信息不生效
}

额外说明

  • 如果需要全局严格一致的限流(跨Edge实例生效),单实例LRU缓存不够用,建议改用Redis等分布式缓存方案。
  • 按IP限流比全局固定token更合理,避免单个用户耗尽所有配额。

内容的提问来源于stack exchange,提问作者jakewilson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 14:45:04