正文边缘限流是防止暴力尝试与滥用的关键控制。本文在 Next.js 15 的中间件中实现令牌桶限流与标准化响应头,适用于公共 API 与登录、验证码等敏感端点。

一、令牌桶实现与中间件接入import { NextRequest, NextResponse } from 'next/server'

type State = { tokens: number; updatedAt: number }

const CAPACITY = 60

const REFILL_PER_SEC = 1

const store: Map<string, State> = (globalThis as any).__rl_store || new Map()

;(globalThis as any).__rl_store = store

function ipOf(req: NextRequest) {

const xff = req.headers.get('x-forwarded-for') || ''

const cfip = req.headers.get('cf-connecting-ip') || ''

const ip = (xff.split(',')[0] || cfip || '0.0.0.0').trim()

return ip

}

function allow(ip: string) {

const now = Date.now()

const st = store.get(ip) || { tokens: CAPACITY, updatedAt: now }

const elapsed = Math.max(0, (now - st.updatedAt) / 1000)

const refill = Math.floor(elapsed * REFILL_PER_SEC)

st.tokens = Math.min(CAPACITY, st.tokens + refill)

st.updatedAt = refill > 0 ? now : st.updatedAt

if (st.tokens <= 0) {

store.set(ip, st)

return { ok: false, resetSec: Math.ceil((CAPACITY - st.tokens) / REFILL_PER_SEC) }

}

st.tokens -= 1

store.set(ip, st)

return { ok: true, remaining: st.tokens }

}

export function middleware(req: NextRequest) {

const ip = ipOf(req)

const result = allow(ip)

if (!result.ok) {

return new NextResponse('Too Many Requests', {

status: 429,

headers: {

'Cache-Control': 'no-store',

'Retry-After': String(result.resetSec),

'RateLimit-Limit': String(CAPACITY),

'RateLimit-Remaining': '0',

'RateLimit-Reset': String(result.resetSec)

}

})

}

const res = NextResponse.next()

res.headers.set('RateLimit-Limit', String(CAPACITY))

res.headers.set('RateLimit-Remaining', String(result.remaining || 0))

res.headers.set('RateLimit-Reset', '1')

res.headers.set('Cache-Control', 'no-store')

return res

}

二、治理要点标准头:返回 `RateLimit-*` 与 `Retry-After`,便于客户端与网关协同退避。缓存策略:统一 `Cache-Control: no-store` 避免 429 被误缓存。识别来源:优先 `x-forwarded-for`,其次 `cf-connecting-ip`;如有代理需在边缘正确透传。细粒度:对高风险端点(登录、验证码、敏感 API)可配置更小容量与更严格窗口。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部