Skip to main content

解析器错误以 HTTP 200 返回

这是你在编写错误处理之前需要了解的最重要的一点。 根据 GraphQL over HTTP 规范,到达我们解析器的请求即使操作失败也会返回 HTTP 200。失败信息在响应体中报告,而不是通过状态码体现。 因此,下面这种检查是无效的:
请改为检查响应体。少数传输错误(例如不支持的 Content-Type 导致的 415)的响应体为空,因此在解析之前请先检查响应是否为 JSON:
有些失败会在任何操作运行之前就被捕获。这些失败都不会到达解析器,也不会消耗 API 调用:
  • 格式错误的请求会返回错误状态码:JSON 无效或缺少 query 时返回 HTTP 400,请求体超过 64 KB 时返回 413,使用 POST 以外的方法时返回 405,Content-Type 不受支持时返回 415。
  • 对 schema 无效的查询只有在你的请求发送了 Accept: application/graphql-response+json 时才会返回 HTTP 400。这包括语法错误、未知字段、参数类型错误、无效的枚举值,以及超出查询限制的查询。如果你发送的是 Accept: application/json,或未发送 Accept header,同样的错误会返回 HTTP 200。无论哪种情况,响应体中都会有 errors 数组,且没有 data。
一旦开始执行,解析器级别的输入验证错误和 API 失败(包括身份验证、授权、上游速率限制以及上游 5xx 响应)都会返回 HTTP 200 以及 errors 数组。

错误结构

每个解析器错误都会在 extensions 中携带类似 HTTP 的 API 状态码:
  • message:人类可读的描述。我们会从解析器错误消息中移除 API Key 和其他凭据,但与你发送的值相关的错误(例如类型错误的变量)可能会重复该值。在记录 message 之前,请将其视为可能包含敏感信息。
  • path:查询中失败的字段。当一个请求中有多个字段时,可以据此判断是哪一个失败了。
  • extensions.status:等效 REST 调用会返回的 HTTP 状态码。请根据它进行分支处理。
  • extensions.code:Ayrshare 数字错误代码(当底层端点提供时)。
  • extensions.retryAfter:在上游配额或速率限制导致的 429 中,如果有可用的重试延迟,则会出现该字段。每请求分派预算导致的 429 中不会出现该字段。
请结合错误代码参考使用 extensions.code,或将其传给 explainError。

部分成功

如果一个请求需要获取多项内容,而只有部分成功,你会同时收到 data 和 errors:
history 已成功,其数据可以使用。只有 analytics 需要重试。不要因为存在 errors 就丢弃整个响应,否则你会丢掉已经计费的数据。

多社交网络帖子的部分成功

发布到多个社交网络的帖子可能在部分社交网络上成功,而在其他社交网络上失败。这种情况不会作为 GraphQL 错误报告,因为操作本身是成功的:它完全按照你的要求执行,并告诉你发生了什么。 结果会区分三种结果:
  • postIds:已发布的社交网络及其帖子 URL。仅包含成功项。
  • errors:失败的社交网络及失败原因。
  • blocked:在尝试之前就被阻止的社交网络,例如在多次确定性失败后被按社交网络划分的熔断器阻止。这些与向服务提供方尝试后返回错误的情况是分开的。
只要任何一个社交网络失败,status 就为 "error",因此它并不能可靠地表明没有任何内容被发布。请读取 postIds 以了解哪些已发布。

重试

GraphQL API 从不自动重试。 如果请求失败,系统不会在你不知情的情况下代你再次尝试。 这一点对变更最为重要。createPost 提供了 idempotencyKey:请在第一次尝试之前生成一个唯一的键,然后在每次重试时复用相同的键和完全相同的负载。已完成处理的重试会重放原始结果,而不是重复写入。在收到不明确的响应后,不要换用新的键。 boostFacebookPost 和 instagramBoostPost 也接受 idempotencyKey,它保护的是真金白银。使用相同的键和相同参数进行重试时,会返回原始结果并标记 idempotentReplayed: true,而不会创建并支付第二个广告。一个键覆盖你的整个账户在两个 Meta 平台上的使用,因此切勿将 Facebook 推广的键复用于 Instagram 推广。 当键被拒绝时,extensions.status 会告诉你原因。createPost 在第一次尝试仍在处理时返回 409,此时请等待并使用相同的键重试;当负载与第一次尝试不同时返回 400。推广类变更在这两种情况下都返回 409,当该键已被用于另一个平台上的推广时也会返回 409。 其他写入操作(例如 addComment)没有幂等键。如果它们的响应丢失,请先检查社交网络或 API 状态,再决定是否可以安全地再次尝试。 有两种不同的限制都会报告 429,需要分别处理。分派预算只会在同一请求中已经启动五次 API 调用后拒绝根字段,其消息以 Query exceeds the per-request dispatch budget 开头:请将这些字段拆分到每个最多包含五个字段的请求中,无需等待。其他任何 429 都是速率限制或配额:如果存在 extensions.retryAfter,请等待相应秒数,否则请在重试前进行退避,并且只重试失败的字段。对于读取操作的 5xx,重试是安全的,但有一个例外:generatePost 虽然是查询,但重试会再次调用 AI 生成器,计为另一次 API 调用,并返回不同的文本。对于没有幂等保护的写入操作的 5xx,请在重试前核实该操作是否已生效。

常见状态码

GraphQL 本身在执行前抛出的错误(例如未知字段、参数类型错误或无效的枚举值)没有 extensions.status。如上所述,根据你的 Accept header,它们会返回 HTTP 400 或 200。这些错误表示查询本身有误,不会发起 API 调用,也不会计费。