错误响应

标准错误响应

如果 Tag Manager API 请求成功,该 API 会在响应正文中随请求的数据一并返回 200 HTTP 状态代码。

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

400 invalidParameter

{
 "error": {
  "errors": [
   {
    "domain": "usageLimits",
    "reason": "accessNotConfigured",
    "message": "Access Not Configured. Please use Google Developers Console to activate the API for your project.",
   }
  ],
  "code": 403,
  "message": "Access Not Configured. Please use Google Developers Console to activate the API for your project."
 }
}

注意:说明随时可能发生变化,因此应用不应受实际说明文字的局限。

实现指数退避

指数退避是指客户端按照不断增加的时间间隔定期重试失败的请求的过程。这是网络应用的标准错误处理策略。Tag Manager 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 是一个小于或等于 1000 的随机毫秒数。必须这样做才能在一些并行实现中避免某些锁定错误。 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(tagmanager):
  """Wrapper to request Google Tag Manager data with exponential backoff.

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

  Args:
    tagmanager: The tagmanager service object

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

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

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