错误

错误和其他响应一样都是 JSON,带有相应的 HTTP 状态码和一个可用于分支判断的代码。消息是写给您的日志看的一句话,而不是给您的用户看的;其措辞可能会变,代码则永远不会变。

错误结构

{
  "status": "error",
  "error": {
    "code": "invalid_request",
    "message": "Parameter 'lat' must be a number between -90 and 90.",
    "param": "lat"
  }
}

当某个特定参数导致问题时,会出现 param。错误响应中同样设置了 X-Request-Id;联系支持时请附上它。

代码

HTTPcode触发条件处理方法
400invalid_request缺少必填参数、值格式错误或超出范围、批量中的点或地址超过 100 个、请求的结果数超过 10 个。修正请求。不要原样重试。
401missing_key未发送密钥,且此服务器已关闭无密钥访问。默认情况下该功能是开启的,不带密钥的请求会正常得到响应。X-API-Key、Bearer 令牌或 key= 发送密钥。
429quota_exceeded该地址当天已用完无密钥的 2,500 个免费请求。等待重置(Retry-AfterX-Quota-Reset 会说明时间),或发送一个有额度或属于 Unlimited 套餐的密钥。
401invalid_key密钥不存在。检查是否有拼写错误或复制不完整。
401key_revoked该密钥已在控制台中被撤销。使用当前有效的密钥。
402no_credits该密钥当天的免费配额已用完,且账户额度余额为零。在控制台中通过银行卡或加密货币充值,或等待重置。
403key_ip_limit该密钥的所有 IP 名额在接下来一段时间内都被其他地址占用。使用已占用名额的机器之一,为这台机器单独配一个密钥,或添加一个套餐。请参阅IP 名额
403account_suspended账户已被暂停。查看我们发给您的电子邮件,或提交工单。
404not_found路径不存在。没有匹配项的查询返回 200 和空结果,而不是 404检查路径和版本前缀。
500server_error我们这边出了问题。一秒后重试一次。该错误会被记录并向我们发出警报。不计数。
503unavailable某个后端暂时不可用。使用退避策略重试。不计数。

不属于错误的情况

兼容替换主机上的错误

兼容替换主机以原服务商使用的结构返回错误,因此现有的错误处理可以正常工作。例如,额度余额为零时,在 gapi.mygeocode.com 上返回 HTTP 200 和 "status": "OVER_QUERY_LIMIT",在 bing.mygeocode.com 上返回 Bing 响应结构中的 "statusCode": 429,在 ipapi.mygeocode.com 上返回 {"status":"fail","message":"quota"};密钥错误时则分别返回 REQUEST_DENIED401invalid key。无论如何,所有主机都会发送 X-Quota-* 响应头,因此如果需要,您可以从响应头读取真实状态。

一种合理的处理策略

def call(url, params, tries=3):
    for attempt in range(tries):
        r = session.get(url, params=params, timeout=10)
        if r.status_code == 200:
            return r.json()
        body = r.json()
        code = body["error"]["code"]
        if r.status_code in (500, 503):
            time.sleep(0.2 * (2 ** attempt))
            continue
        # no_credits, key_ip_limit, invalid_request, invalid_key: retrying will not help
        raise ApiError(code, body["error"]["message"], r.headers.get("X-Request-Id"))
    raise ApiError("retries_exhausted", "Gave up after %d attempts" % tries, None)