Python脚本调用REST API首次成功后每60秒崩溃求助排查
定时调用REST API反复触发JSON解析错误的问题排查
问题现象
现有一个每60秒调用REST API的Python脚本,首次请求可成功,但后续每次请求都会触发错误处理逻辑,报错信息为Expecting value: line 1 column 1 (char 0)。脚本及输出如下:
原脚本
import json import time from datetime import datetime, timedelta import http.client payload = "" # 省略实际内容 headers = {} # 省略实际内容 def get_conn(): try: ms = datetime.now() - timedelta(days=xxx) current_time = time.mktime(ms.timetuple()) ms = datetime.now() current_time2 = time.mktime(ms.timetuple()) api_Url = "xxxxxx".format(int(xxxx), int(xxxx)) conn = http.client.HTTPSConnection("xxxxx") conn.request("GET", api_Url, payload, headers) print('Getting response...') res = conn.getresponse() data = res.read() data = data.decode("utf-8") data = json.loads(data) return data except Exception as e: handle_crash(e) def handle_crash(e): print('Restarting in 60 seconds ' + str(e)) time.sleep(60) # Restarts the script after 60 seconds start() def start(): while True: data = get_conn() time.sleep(60) start()
脚本输出
Getting response... Restarting in 60 seconds Expecting value: line 1 column 1 (char 0) Getting response... Restarting in 60 seconds Expecting value: line 1 column 1 (char 0) Getting response... Restarting in 60 seconds Expecting value: line 1 column 1 (char 0)
问题原因分析
JSON解析失败的直接原因:
Expecting value: line 1 column 1错误表明json.loads()接收到的是空字符串或非JSON格式内容。这意味着后续请求中,API返回的响应不是有效的JSON,甚至没有返回内容。潜在的脚本缺陷:
- 未检查API响应状态码:首次请求成功后,后续请求可能因限流(429)、服务器错误(500)或认证失效,返回错误页面/空内容,却被直接尝试解析为JSON。
- 未正确关闭HTTP连接:
http.client.HTTPSConnection未主动关闭,可能导致连接复用失效,服务器端关闭闲置连接后,后续请求返回空响应。 - 错误处理逻辑递归调用:
handle_crash()中直接调用start()会创建嵌套的while True循环,引发逻辑混乱,甚至栈溢出风险。
解决方案
优化后的脚本
import json import time from datetime import datetime, timedelta import http.client payload = "" # 替换为实际请求体 headers = {} # 替换为实际请求头(如认证、Content-Type等) def get_conn(): # 时间参数计算 ms_past = datetime.now() - timedelta(days=xxx) current_time = int(time.mktime(ms_past.timetuple())) current_time2 = int(time.mktime(datetime.now().timetuple())) api_url = "xxxxxx".format(current_time, current_time2) # 替换为实际API路径模板 conn = http.client.HTTPSConnection("xxxxx") # 替换为实际API域名 try: conn.request("GET", api_url, payload, headers) print('Getting response...') res = conn.getresponse() # 先检查响应状态码 if res.status not in (200, 201): error_content = res.read().decode("utf-8") raise Exception(f"API请求失败,状态码: {res.status},响应内容: {error_content}") # 读取并解析响应 data = res.read().decode("utf-8") if not data: raise Exception("API返回空响应") return json.loads(data) finally: # 确保连接无论成功失败都关闭 conn.close() def start(): while True: try: data = get_conn() # 此处添加对返回数据的处理逻辑 print(f"成功获取数据: {data}") time.sleep(60) except Exception as e: print(f'请求出错: {str(e)},60秒后重试...') time.sleep(60) start()
关键优化点
- 增加响应状态码校验:先判断API返回是否成功,避免无效内容进入JSON解析步骤。
- 强制关闭HTTP连接:使用
finally块确保每次请求后关闭连接,避免连接复用问题。 - 重构错误处理逻辑:将重试逻辑放在
start()的主循环中,避免递归调用导致的嵌套循环问题。
额外排查建议
- 在调试阶段,打印完整的API响应内容,确认后续请求失败时的具体返回。
- 检查API的调用频率限制,确认是否超过阈值导致限流。
- 验证请求头中的认证信息(如Token)是否有效,是否存在过期或失效情况。
内容的提问来源于stack exchange,提问作者redoc01
相关产品推荐
相关产品推荐

