---

title: GraphQL查询复杂度与深度限制(cost-limit/速率协同)最佳实践

keywords:

  • GraphQL
  • 复杂度
  • 深度限制
  • 速率协同
  • Query成本

description: 通过计算查询复杂度与深度并与速率限制协同门禁,防止高成本查询导致资源耗尽与滥用。

categories:

  • 文章资讯
  • 技术教程

---

背景与价值

GraphQL易被构造高成本查询。统一复杂度与深度限制并与速率策略协同,可在入口阻断滥用。

统一规范

  • 深度上限:例如最大深度5。
  • 复杂度上限:为字段赋予成本权重并聚合,超限拒绝。
  • 速率协同:成本高的请求降低速率阈值。

核心实现

AST简化与复杂度计算(示意)

type Node = { name: string; children?: Node[] }

const weight: Record<string, number> = { user: 1, users: 3, posts: 2, comments: 3, profile: 1 }

function depth(node: Node): number { if (!node.children || node.children.length === 0) return 1; return 1 + Math.max(...node.children.map(depth)) }

function cost(node: Node): number { const w = weight[node.name] || 1; const child = (node.children || []).reduce((s, n) => s + cost(n), 0); return w + child }

function withinLimits(root: Node, maxDepth: number, maxCost: number): boolean { return depth(root) <= maxDepth && cost(root) <= maxCost }

速率协同门禁

function bucket(costVal: number): number { if (costVal <= 10) return 10; if (costVal <= 30) return 5; return 2 }

class Rate {
  tokens = new Map<string, { left: number; resetAt: number }>()
  now(): number { return Date.now() }
  refill(k: string, capacity: number, windowMs: number) { const r = this.tokens.get(k); const n = this.now(); if (!r || n >= r.resetAt) this.tokens.set(k, { left: capacity, resetAt: n + windowMs }) }
  take(k: string): boolean { const r = this.tokens.get(k); if (!r) return false; if (r.left <= 0) return false; r.left--; return true }
}

function gateRate(rate: Rate, id: string, costVal: number): boolean { const cap = bucket(costVal); rate.refill(id, cap, 60000); return rate.take(id) }

落地建议

  • 为核心字段设置成本权重并统一深度上限,按业务场景调整阈值。
  • 将复杂度结果与速率限制协同,动态限流高成本查询以防资源耗尽。
  • 审计拒绝事件与高成本请求路径,持续优化Schema与字段权重。

验证清单

  • 查询深度与复杂度是否在上限内,速率是否按成本动态调整。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部