Skip to main content
Fluz 不按套餐出售 API 配额——不存在”免费版 = X 请求/分钟,专业版 = Y 请求/分钟”这样的分级,也没有按密钥划分的配额系统。相反,每个服务都会应用保护性速率限制,以吸收滥用流量并保护其后端。正常的交互流量和应用流量实际上不会触发这些限制;它们的作用是拦截失控脚本和滥用行为。 GraphQL API 还会限制单次查询可以请求的内容量,以成本点数衡量。该限制与请求速率限制是分开的,失败方式也不同。请参阅下文的查询成本限制。
目前没有可申请提高的公开分级配额。如果一个行为良好的集成仍然触发了限制,这通常说明有值得修复的流量模式(参见构建行为良好的客户端),而不是需要提高的配额。

限制的应用方式

限制是按服务独立执行的,并且会在该服务的所有实例之间进行全局评估——你无法通过切换到另一台服务器来绕开限制。请求会通过以下组合来识别:
  • 你的 IP 地址——每个请求都会计入按 IP 划分的限制。
  • 你的访问令牌——完整的 Authorization 请求头。令牌限制是在 IP 限制之上额外应用的,而不是取代它。IP 限制会先被检查,因此来自同一 IP 的每个请求都会共享该 IP 的额度,无论携带什么令牌。没有认证请求头的请求会跳过令牌限制器。
  • 端点路径——在部分公开接口上,特定路径有各自独立的限制。
超出请求速率限制会返回 HTTP 429 Too Many Requests。

按接口划分的流量限制

这些是持续的每秒请求限制。超出后,该密钥会被短暂冷却封锁,之后才能重新接受请求。
大多数集成都会调用 GraphQL API 端点来完成存款、购买、转账和查看操作——请围绕该端点每秒 20 次请求来做规划。移动端/应用网关的按 IP、按令牌和按端点限制会按环境单独配置,并未公布为固定数值;请将其视为保护性限制,在遇到 429 时进行退避。

查询成本限制

GraphQL API 会在每个查询运行之前对其打分。只要查询超出以下任意一项限制,无论发送请求的速度多慢,都会在运行前被拒绝。

成本是如何计算的

你选择的每个字段花费 1 点。拥有自己选择集的字段花费 1 点,再加上其内部所有内容成本的 5 倍,而一个查询的成本是其顶层字段成本之和。每一层嵌套都会把下面的内容乘以 5:
最深层的字段成本最高。顶层字段花费 1 点,第五层的字段花费 625 点,而第六层(深度限制所允许的最深层级)的字段花费 3,125 点。第五层有 11 个字段,或第六层有 2 个字段,就会让查询超出 7,000。实际使用中,你会先达到成本限制,而不是深度限制。
  • 分页大小不会改变成本。请求 1 行还是 20 行成本相同,因为成本来自你选择的字段,而不是返回的行数。
  • __typename 的花费与其他字段相同。像 Apollo Client 这样默认会把它加入每个选择集的客户端,会提高深层查询的成本。
  • 片段会增加层级。内联片段(... on Type { })算作一层嵌套,命名片段展开算作两层,因此片段内的相同字段成本会变成 5 倍或 25 倍。在大型查询中应就地写出字段,而不是使用片段。
  • 文档中的每个操作都会被检查,包括 operationName 未选中的操作。只要有一个操作超出限制,整个请求都会被拒绝。

查询被拒绝时

响应为 HTTP 400,原因会包含在 errors 数组中:
尽管查询本身是合法的 GraphQL,消息仍以 Syntax Error 开头,其中 found 的值就是你查询的成本。别名和指令限制会以相同的结构返回各自的消息,例如 Syntax Error: Aliases limit of 15 exceeded, found 16.。超出深度限制的查询也一定会超出成本限制,因此会同时收到两个错误,成本错误在前。超出令牌限制的请求会返回 HTTP 500,代码相同;批处理请求会返回 HTTP 400,代码为 BAD_REQUEST,消息为 Operation batching disabled.。 查询被拒绝时不会执行任何操作,因此不会应用任何变更操作,再次发送相同的查询会返回相同的错误。

身份验证与安全

登录、PIN 和双重验证(2FA)流程与一般 API 流量分开保护。重复失败的尝试——登录、PIN 校验或 2FA 验证——以及过多的 2FA 或短信请求,会触发临时锁定,锁定会在冷却期结束后自动解除。成功的身份验证会重置这些计数器。
不要自动重试失败的登录、PIN 校验或 2FA。向用户展示“请稍后再试”的状态提示——自动重试会延长锁定时间。

超出限制时

速率限制和查询成本限制的失败方式不同,因此重试前请先检查状态: 每个被限流的响应都使用状态码 429 Too Many Requests。响应体和响应头会因接口而异:
响应头的可用性并不统一:
  • Retry-After(整数秒)会在身份验证 IP 限制器和 PIN/2FA 流程中返回。在一般的 GraphQL/Web 流量限制器上,不保证会返回该响应头。
  • 目前没有 X-RateLimit-Limit、X-RateLimit-Remaining 或 X-RateLimit-Reset 响应头——不要构建依赖它们的逻辑。

构建行为良好的客户端

1

将 429 视为可重试

如果存在 Retry-After,请遵循它。如果不存在,请从大约 1 秒开始做指数退避(1 秒 → 2 秒 → 4 秒……),而不是立即重试。
2

保持持续速率适中

不要从单个 IP 或令牌向某个接口并发发送大量请求。对于 GraphQL API,请将速率保持在明显低于每秒 20 次请求的水平,并平滑突发流量。
3

保持查询精简

只选择你会用到的字段,保持嵌套较浅,并在大型查询中就地写出字段,而不是使用片段。如果查询触及成本限制,请将其拆分为更小的查询,而不是重试。
4

不要自动重试身份验证失败

重复的登录、PIN 或 2FA 失败会导致临时锁定。请向用户显示“请稍后再试”的提示,而不是自动重试。
5

按 IP 而非按令牌分配额度

来自同一 IP 的每个请求都计入同一个限制,无论你使用了多少个令牌。如果多个工作进程、服务或客户账户通过同一个 NAT 网关或代理发送流量,请将它们统一调度节奏,使合计速率保持在限制以内。
由于 Retry-After 并非在所有场景下都能保证返回,请将重试逻辑与幂等键结合使用,确保重试的变更操作不会导致购买或转账被重复处理。完整的错误目录参见错误。