错误
错误和其他响应一样都是 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;联系支持时请附上它。
代码
| HTTP | code | 触发条件 | 处理方法 |
|---|---|---|---|
| 400 | invalid_request | 缺少必填参数、值格式错误或超出范围、批量中的点或地址超过 100 个、请求的结果数超过 10 个。 | 修正请求。不要原样重试。 |
| 401 | missing_key | 未发送密钥,且此服务器已关闭无密钥访问。默认情况下该功能是开启的,不带密钥的请求会正常得到响应。 | 以 X-API-Key、Bearer 令牌或 key= 发送密钥。 |
| 429 | quota_exceeded | 该地址当天已用完无密钥的 2,500 个免费请求。 | 等待重置(Retry-After 和 X-Quota-Reset 会说明时间),或发送一个有额度或属于 Unlimited 套餐的密钥。 |
| 401 | invalid_key | 密钥不存在。 | 检查是否有拼写错误或复制不完整。 |
| 401 | key_revoked | 该密钥已在控制台中被撤销。 | 使用当前有效的密钥。 |
| 402 | no_credits | 该密钥当天的免费配额已用完,且账户额度余额为零。 | 在控制台中通过银行卡或加密货币充值,或等待重置。 |
| 403 | key_ip_limit | 该密钥的所有 IP 名额在接下来一段时间内都被其他地址占用。 | 使用已占用名额的机器之一,为这台机器单独配一个密钥,或添加一个套餐。请参阅IP 名额。 |
| 403 | account_suspended | 账户已被暂停。 | 查看我们发给您的电子邮件,或提交工单。 |
| 404 | not_found | 路径不存在。没有匹配项的查询返回 200 和空结果,而不是 404。 | 检查路径和版本前缀。 |
| 500 | server_error | 我们这边出了问题。 | 一秒后重试一次。该错误会被记录并向我们发出警报。不计数。 |
| 503 | unavailable | 某个后端暂时不可用。 | 使用退避策略重试。不计数。 |
不属于错误的情况
- 没有结果。对无意义文本进行正向地理编码会返回
200和"results": []。在海洋中进行逆地理编码会返回200和"result": null。两者都计为一次请求。 - 精度较低。当您想要门牌地址却得到
"precision": "admin"的结果时,这是一个成功的请求,只是找到的比您期望的少。请检查该字段。 - 私有 IP 地址。查询
10.0.0.1会返回200和"is_private": true,不含位置信息。
兼容替换主机上的错误
兼容替换主机以原服务商使用的结构返回错误,因此现有的错误处理可以正常工作。例如,额度余额为零时,在 gapi.mygeocode.com 上返回 HTTP 200 和 "status": "OVER_QUERY_LIMIT",在 bing.mygeocode.com 上返回 Bing 响应结构中的 "statusCode": 429,在 ipapi.mygeocode.com 上返回 {"status":"fail","message":"quota"};密钥错误时则分别返回 REQUEST_DENIED、401 和 invalid 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)