← 中文资源

简体中文版本

追踪 GraphQL 操作用量以发现滥用查询

按名称与哈希为每个 GraphQL 操作建立指纹,聚合调用次数与深度,揪出发送超大或无界查询的客户端。

阅读英文原文

目标

REST 访问日志天然带端点名,吵闹的客户端一次 sort 就现形;而没有操作名的 GraphQL 只会给你一整面 POST /graphql 的墙。指纹化解决了这个问题:为每个请求记录操作名与规范化查询文本的哈希,一天之内你就能拿到“谁在真实使用 API、每种形状有多贵”的排行榜。

步骤要点

  1. 在 Apollo Server 插件的 willSendResponse 里输出操作名(匿名则记 anonymous)、查询文本哈希前 12 位与嵌套深度到结构化日志。
  2. 用 jq 聚合 name+hash 出现次数并降序排列,找出调用量最大的操作,逼近榜首的匿名哈希就是没署名的大户。
  3. 再按深度排序:列表字段上 12 层嵌套立刻显形,解释了单请求成本离群的原因。
  4. 给服务端加 depthLimit(8) 校验规则,超深匿名查询被明确拒绝,第三方被迫注册具名且经评审的操作。
  5. 持续观察排行榜变化,把新增的高频操作逐步迁入持久化查询注册表。

排错提示

匿名查询占大头时,对一方客户端在 CI 里强制操作命名,对第三方启用持久化查询只发哈希;深度高但成本低说明分支只返回标量,应结合字段级成本权重再拒绝;同一逻辑查询哈希漂移是空白与注释造成的,需先用 graphql print 规范化再哈希或改用操作名加变量签名。

适用边界

指纹看到的是查询文本而非执行成本,看似便宜的查询配上传入的大变量值依然昂贵;持久化查询需要注册表工具链,并给客户端增加一个发布步骤。

代码示例

# Rank operations by volume
grep '"op"' access.log | jq -r '.name + " " + .hash' \
  | sort | uniq -c | sort -rn | head -15