错误响应

标准错误响应

如果 Reporting API 请求成功,API 会返回 200。如果请求出现错误,该 API 会根据错误类型在响应中返回 HTTP 状态代码、状态和原因。此外,响应正文还将详细说明出错的原因。下面是一个错误响应示例:

{
 "error": {
  "code": 403,
  "message": "User does not have sufficient permissions for this profile.",
  "status": "PERMISSION_DENIED"
 }
}

错误表

代码 状态 说明 建议采取的操作
400 INVALID_ARGUMENT 请求无效;必需的参数可能会丢失、超出限制或包含无效值。 查看错误消息以获取详细信息。如果客户端进行重试,此错误将再次失败。
401 UNAUTHENTICATED 客户端没有进行正确的身份验证。 在解决问题之前,请勿重试。您需要获取新的身份验证令牌。
403 PERMISSION_DENIED 表示请求用户无权访问的数据。 在解决问题之前,请勿重试。您需要获取足够的权限,才能对指定实体执行相应操作。
429 RESOURCE_EXHAUSTED AnalyticsDefaultGroupCLIENT_PROJECT-1d 表明每项目每天请求数 配额已经用尽。 在解决问题之前,请勿重试。您的每日配额已用尽。
429 RESOURCE_EXHAUSTED AnalyticsDefaultGroupCLIENT_PROJECT-100s 表明每项目每 100 秒请求数配额已经用尽。 使用指数退避算法重试。您需要降低发送请求的速率。
429 RESOURCE_EXHAUSTED AnalyticsDefaultGroupUSER-100s 表明每项目每用户每 100 秒请求数配额已经用尽。 使用指数退避算法重试。您需要降低发送请求的速率。
429 RESOURCE_EXHAUSTED DiscoveryGroupCLIENT_PROJECT-100s 表明每 100 秒发现请求数配额已经用尽。 发现响应不经常更改;请在本地缓存发现响应或使用指数退避算法重试。您需要降低发送请求的速率。
500 INTERNAL 发生了内部服务器意外错误。 此查询的重试次数不得超过一次。
503 BACKEND_ERROR 服务器返回了一个错误。 此查询的重试次数不得超过一次。
503 UNAVAILABLE 该服务无法处理此请求。 这很可能是一种暂时情况,可以通过指数退避重试来纠正。

实现指数退避

指数退避是指客户端按照不断增加的时间间隔定期重试失败的请求的过程。这是网络应用的标准错误处理策略。报告 API 在设计时就已考虑到了客户端可能会使用指数退避重试失败的请求。这除了是一项“要求”外,使用指数退避还能提高带宽使用效率、减少获得成功响应所需的请求数,并最大程度地提高并发环境中的请求吞吐量。

实现简单指数退避的流程如下。

  1. 向 API 发出请求
  2. 接收错误响应,其中包含一个可重试的错误代码
  3. 等待 1 秒 + random_number_milliseconds
  4. 重试请求
  5. 接收错误响应,其中包含一个可重试的错误代码
  6. 等待 2 秒 + random_number_milliseconds
  7. 重试请求
  8. 接收错误响应,其中包含一个可重试的错误代码
  9. 等待 4 秒 + random_number_milliseconds
  10. 重试请求
  11. 接收错误响应,其中包含一个可重试的错误代码
  12. 等待 8 秒 + random_number_milliseconds
  13. 重试请求
  14. 接收错误响应,其中包含一个可重试的错误代码
  15. 等待 16 秒 + random_number_milliseconds
  16. 重试请求
  17. 如果错误仍然出现,则停止重试并记录错误。

在上述流程中,random_number_milliseconds 是小于或等于 1, 000 的随机毫秒数。必须这样做才能在一些并行实现中避免某些锁定错误。random_number_milliseconds 必须在每次等待后重新定义。

注意:等待时间始终是 (2 ^ n) + random_number_milliseconds,其中 n 是单调递增的整数,初始值为 0。n 在每次迭代(每次请求)后递增 1。

该算法设置为 n 为 5 时终止。设置这个上限只是为了防止客户端无限重试,以便在大约总共 32 秒的延迟后,将请求认定为“不可恢复的错误”。

下面的 Python 代码就是上述流程的实现示例,旨在从名为 makeRequest 的方法出现的错误中恢复过来。

import random
import time
from apiclient.errors import HttpError

def makeRequestWithExponentialBackoff(analytics):
  """Wrapper to request Google Analytics data with exponential backoff.

  The makeRequest method accepts the analytics service object, makes API
  requests and returns the response. If any error occurs, the makeRequest
  method is retried using exponential backoff.

  Args:
    analytics: The analytics service object

  Returns:
    The API response from the makeRequest method.
  """
  for n in range(0, 5):
    try:
      return makeRequest(analytics)

    except HttpError, error:
      if error.resp.reason in ['userRateLimitExceeded', 'quotaExceeded',
                               'internalServerError', 'backendError']:
        time.sleep((2 ** n) + random.random())
      else:
        break

  print "There has been an error, the request never succeeded."