限制 GraphQL 查询深度的正确方式

发布: (2026年1月16日 GMT+8 03:20)
5 min read
原文: Dev.to

I’m happy to translate the article for you, but I need the full text you’d like translated. Could you please paste the content (excluding the source line you’ve already provided) here? Once I have the article text, I’ll translate it into Simplified Chinese while preserving the formatting, markdown, and code blocks.

介绍 graphql‑safe‑depth

GraphQL 功能强大、灵活且表达力丰富——但如果查询没有得到适当约束,这种灵活性可能会成为隐患。
过深的查询会导致解析器执行过多、内存使用过高,甚至出现拒绝服务(DoS)场景。

在本文中,你将了解:

  • 为什么深层 GraphQL 查询是一个真实的问题
  • 为什么许多现有的深度限制方案效果不佳
  • graphql‑safe‑depth 如何以不同的方式解决该问题
  • 如何在 Apollo Server 和 NestJS 中使用它
  • 何时以及如何将其与其他安全措施相结合

🚨 问题:深层 GraphQL 查询

query {
  user {
    posts {
      comments {
        author {
          profile {
            avatar {
              url
            }
          }
        }
      }
    }
  }
}

乍一看这看似无害,但它可能会:

  • 触发 N+1 查询爆炸
  • 消耗大量 CPU 和内存
  • 成为 DoS 向量,无论是有意还是无意

GraphQL 并未默认设置任何深度或复杂度限制。

🤔 为什么现有解决方案不足

问题描述
❌ 统计字段数量而非执行深度一些库统计字段的总数,而不是最深的执行路径,这会导致误报或令人困惑的行为。
❌ 破坏自省自省查询(__schema__type__typename)本质上往往很深,不应被阻止。
❌ 难以推理某些实现难以定制、调试或向团队解释。

✅ 方法:graphql‑safe‑depth

graphql‑safe‑depth 是一个轻量级的 GraphQL 验证规则,专注于一件事:

  • 🧠 测量最深的解析器路径
  • 🔍 默认忽略 introspection 字段
  • 🧩 完全支持 fragments(片段)
  • ⚡ 零运行时依赖
  • 🛠 TypeScript 为先,兼容 JavaScript

工作原理

  1. 该库挂钩到 GraphQL 的 validation phase(验证阶段)
  2. 它遍历查询的 AST(抽象语法树)。
  3. 根据嵌套的字段选择计算深度。
  4. 记录最大执行深度。
  5. 如果深度超过 maxDepth,查询将在 执行前 被拒绝。

深度计算示例

✅ 有效查询(depth = 3)

query {
  user {
    profile {
      name
    }
  }
}

❌ 无效查询(depth = 4)

query {
  user {
    profile {
      address {
        city
      }
    }
  }
}

只有最深的执行路径重要——而不是字段的总数。

🚀 使用示例

Apollo Server (Node.js)

import { ApolloServer } from "apollo-server";
import { createDepthLimitRule } from "graphql-safe-depth";

const server = new ApolloServer({
  typeDefs,
  resolvers,
  validationRules: [
    createDepthLimitRule({ maxDepth: 3 }),
  ],
});

Apollo Server (NestJS)

import { createDepthLimitRule } from "graphql-safe-depth";

GraphQLModule.forRoot({
  autoSchemaFile: true,
  validationRules: [
    createDepthLimitRule({ maxDepth: 3 }),
  ],
});

⚙️ 配置选项

createDepthLimitRule({
  maxDepth: number;               // required
  ignoreIntrospection?: boolean; // default: true
  message?: (depth: number, maxDepth: number) => string; // optional
});
  • maxDepth – 允许的最大执行深度。

    createDepthLimitRule({ maxDepth: 3 });
  • ignoreIntrospection – 为 true 时,忽略 introspection(自省)字段。

    createDepthLimitRule({
      maxDepth: 3,
      ignoreIntrospection: false,
    });
  • message – 自定义验证错误信息。

    createDepthLimitRule({
      maxDepth: 3,
      message: (depth, max) =>
        `Query depth ${depth} exceeds the allowed maximum of ${max}`,
    });

🔐 安全考虑

深度限制 不是 万能钥匙,但它与以下措施配合良好:

  • ✅ 查询复杂度限制
  • ✅ 正确的身份验证和授权
  • ✅ 限流
  • ✅ 缓存和批处理(例如 DataLoader)

graphql‑safe‑depth 专注于做好一件事——以可预测的方式防止危险的深层查询。

📦 安装

npm i graphql-safe-depth

🔗 链接

  • GitHub 仓库:
  • npm 包:

🧠 最后思考

该库最初是作为学习练习而创建的,现已发展为具备稳定 v1.0.0 发行版的生产就绪工具。如果您在生产环境中运行 GraphQL 并且需要一个简单、可预测的深度限制,graphql‑safe‑depth 可能是一个合适的选择。

欢迎提供反馈、提交问题和贡献代码! 🙌

Back to Blog

相关文章

阅读更多 »

我的 Node.js API 最佳实践 2025年

Node.js 已经为生产环境的 API 提供动力超过十年了,在 2025 年,它已经不再是“新”或实验性的,而是基础设施。正是这种成熟度使得 c...

别再像2015年那样写API

我们已经进入2025年,仍有许多代码库把 API 视为简单的“返回 JSON 的端点”。如果你的 API 设计仍停留在基本的 CRUD 路由上,你正……