一、目标与参数支持租户、用户与路由维度的组合Key;最小窗口与上限参数可验证。突发与持续双策略:滑动窗口用于峰值限制,令牌桶用于持续速率。二、滑动窗口class SlidingWindowLimiter { windowMs: number limit: number hits = new Map<string, number[]>() constructor(windowMs: number, limit: number) { this.windowMs = windowMs; this.limit = limit } allow(key: string): { ok: boolean; remaining: number } { const now = Date.now() const arr = (this.hits.get(key) || []).filter(t => now - t < this.windowMs) if (arr.length >= this.limit) return { ok: false, remaining: 0 } arr.push(now) this.hits.set(key, arr) return { ok: true, remaining: Math.max(0, this.limit - arr.length) } } } 三、令牌桶class TokenBucketLimiter { capacity: number refillPerSec: number buckets = new Map<string, { tokens: number; ts: number }>() constructor(capacity: number, refillPerSec: number) { this.capacity = capacity; this.refillPerSec = refillPerSec } allow(key: string): { ok: boolean; tokens: number } { const now = Date.now() const b = this.buckets.get(key) || { tokens: this.capacity, ts: now } const elapsed = (now - b.ts) / 1000 b.tokens = Math.min(this.capacity, b.tokens + elapsed * this.refillPerSec) b.ts = now if (b.tokens < 1) { this.buckets.set(key, b); return { ok: false, tokens: Math.floor(b.tokens) } } b.tokens -= 1 this.buckets.set(key, b) return { ok: true, tokens: Math.floor(b.tokens) } } } 四、组合策略与路由整合type Req = { headers: Record<string, string | undefined>; path: string } type Res = { status: (n: number) => Res; end: (b?: string) => void; setHeader: (k: string, v: string) => void } class CompositeLimiter { win: SlidingWindowLimiter bucket: TokenBucketLimiter constructor(win: SlidingWindowLimiter, bucket: TokenBucketLimiter) { this.win = win; this.bucket = bucket } allow(key: string): boolean { const a = this.win.allow(key) if (!a.ok) return false const b = this.bucket.allow(key) return b.ok } } function keyOf(req: Req): string { const tenant = req.headers['x-tenant-id'] || 'anon' const user = req.headers['x-user-id'] || 'anon' return `${tenant}:${user}:${req.path}` } function rateGuard(limiter: CompositeLimiter) { return function handler(req: Req, res: Res, next: Function) { const key = keyOf(req) if (!limiter.allow(key)) { res.setHeader('Retry-After', '1') return res.status(429).end('rate_limited') } next() } } 五、配额管理class QuotaStore { counts = new Map<string, number>() limit: number constructor(limit: number) { this.limit = limit } add(key: string, n: number): boolean { const v = (this.counts.get(key) || 0) + n if (v > this.limit) return false this.counts.set(key, v) return true } remaining(key: string): number { return Math.max(0, this.limit - (this.counts.get(key) || 0)) } } function quotaGuard(store: QuotaStore) { return function handler(req: Req, res: Res, next: Function) { const key = keyOf(req) const ok = store.add(key, 1) if (!ok) return res.status(403).end('quota_exceeded') next() } } 六、验收清单最小窗口`windowMs≥1000`与滑动上限通过;令牌桶容量与补充速率生效。租户/用户/路由组合Key验证;速率限制返回`429`并包含`Retry-After`。配额计数可靠并可查询剩余;审计记录包含组合Key与路由信息。

发表评论 取消回复