做接口开发时,很多问题并不是请求发不出去,而是请求成功了,但返回的数据和预期不一样。
比如接口返回空数据、状态码异常、字段缺失,或者 HTTP 请求本身正常,但业务结果却失败。
如果代码只判断"有没有返回数据",很容易出现后续程序继续执行,最后才发现问题。
所以接口调用之后,最好统一处理返回结果。
一、不要只判断 HTTP 状态码
例如:
response = requests.post(url, json=data)
if response.status_code == 200:
print("请求成功")
这种判断只能说明 HTTP 层面没有明显错误。
并不能说明业务操作一定成功。
更合理的是继续检查返回内容:
response = requests.post(url, json=data)
if response.status_code != 200:
print("HTTP请求失败")
return
result = response.json()
if not result:
print("返回数据为空")
return
实际项目中,还需要根据接口返回结构判断具体的业务状态。
二、返回数据为空也要处理
有些接口请求成功后,返回的数据可能为空。
例如:
{
"data": null
}
如果代码直接:
name = result["data"]["name"]
就可能直接报错。
可以先判断:
data = result.get("data")
if not data:
print("没有获取到数据")
return
接口返回的数据结构不确定时,提前做判断会更加安全。
三、字段不存在不能直接取
比如正常情况下返回:
{
"data": {
"name": "张三",
"wxid": "wxid_001"
}
}
代码直接:
wxid = result["data"]["wxid"]
如果某次返回里没有 wxid,程序就会抛出异常。
可以使用:
wxid = result.get("data", {}).get("wxid")
if not wxid:
print("wxid不存在")
return
对于接口字段比较多的项目,这种判断非常有必要。
四、JSON解析也可能失败
不要默认接口一定返回 JSON。
例如请求超时、网关异常或者服务器返回错误页面,都可能导致:
result = response.json()
直接报错。
可以单独处理:
try:
result = response.json()
except ValueError:
print("返回内容不是合法JSON")
return
这样至少可以把问题记录下来,而不是让整个程序直接中断。
五、业务失败和请求失败要分开
实际开发中可以把错误简单分成两类。
请求层错误
例如:
-
请求超时
-
网络异常
-
HTTP 状态异常
-
JSON解析失败
业务层错误
例如:
-
参数不正确
-
当前状态不允许操作
-
实例状态异常
-
目标数据不存在
两类问题的处理方式并不一样。
例如请求超时,可以考虑重新请求。
但如果是参数错误,重复请求通常没有意义。
六、不要看到失败就无限重试
比较常见的一种写法:
while True:
result = post_api()
if success:
break
这种方式风险比较大。
如果接口一直失败,程序就会一直请求。
更合理的是限制重试次数:
for i in range(3):
result = post_api()
if success(result):
break
同时记录每一次失败原因。
例如:
第1次:请求超时
第2次:请求超时
第3次:请求成功
这样出现问题时也比较容易排查。
七、不同接口要区别处理
并不是所有接口都适合使用相同的重试方式。
例如:
查询接口
一般可以适当重试。
发送消息接口
需要谨慎处理。
因为第一次请求可能已经执行成功,只是客户端没有及时收到结果。
如果直接再次请求,就可能出现重复操作。
所以对于有实际业务影响的接口,最好考虑请求唯一 ID或者幂等处理。
八、统一封装异常处理
如果每个接口都单独写一遍异常判断,代码很容易重复。
可以统一封装:
def post_api(url, data):
try:
response = requests.post(
url,
json=data,
timeout=15
)
response.raise_for_status()
return response.json()
except requests.Timeout:
return {
"success": False,
"error": "request_timeout"
}
except requests.RequestException as e:
return {
"success": False,
"error": str(e)
}
except ValueError:
return {
"success": False,
"error": "invalid_json"
}
业务代码只需要处理统一结果。
九、日志不要只记录"失败"
下面这种日志:
接口调用失败
实际帮助不大。
至少应该记录:
接口名称
请求时间
请求参数
HTTP状态
返回结果
错误原因
重试次数
例如:
时间:19:42:15
接口:sendMessage
状态:失败
原因:request_timeout
重试次数:2
这样后面定位问题会简单很多。
十、建议给接口结果建立统一结构
如果项目接口比较多,可以统一成类似:
{
"success": True,
"data": {},
"error": None
}
失败时:
{
"success": False,
"data": None,
"error": "request_timeout"
}
业务层就不需要针对每个接口写不同的判断方式。
整体逻辑可以保持:
发起请求 → 判断 HTTP → 解析 JSON → 判断业务状态 → 返回统一结果 → 记录日志
总结
接口异常处理最重要的不是把代码写得复杂,而是把不同层面的错误区分开。
主要注意:
-
不要只判断 HTTP 状态码
-
检查返回数据是否为空
-
判断关键字段是否存在
-
处理 JSON 解析异常
-
区分请求错误和业务错误
-
控制重试次数
-
有副作用的接口谨慎重试
-
统一记录错误日志
这些基础处理做好以后,接口出现异常时,程序不会轻易直接中断,排查问题也会更加方便。