---
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与字段权重。
验证清单
- 查询深度与复杂度是否在上限内,速率是否按成本动态调整。

发表评论 取消回复