Python Aiohttp/Asyncio API请求仅大数据量时触发ContentTypeError排查
问题触发原因
- API速率限制被触发:你当前的实现会一次性创建所有分页的并发请求,小日期范围下总页数少,并发请求数低于Harvest API的限流阈值,所有请求都能正常返回JSON格式数据;当日期范围扩大后,分页总数激增,短时间内大量并发请求触发了API的速率限制,服务端返回HTML格式的限流提示页面(通常为429状态码),而非预期的JSON结构,因此触发JSON解析错误。
- 服务端查询超时:过大的日期查询范围会导致部分请求的服务端处理时间超过网关/接口超时阈值,网关会直接返回HTML格式的5xx错误页面,同样无法解析为JSON。
排查方法
修改get_dataset函数,在解析响应前先打印状态码和原始响应内容,即可定位具体错误:
async def get_dataset(session, url): async with session.get(url=url, headers=headers, params=params) as resp: # 新增调试代码 if resp.status != 200: print(f"请求异常,状态码:{resp.status},响应内容:{await resp.text()}") resp_content_type = resp.headers.get("Content-Type", "") if "application/json" not in resp_content_type: print(f"非预期响应类型:{resp_content_type},响应内容:{await resp.text()}") raise Exception(f"响应类型异常:{resp_content_type}") dataset = await resp.json() return dataset['time_entries']
修复方案
1. 限制并发请求数
使用信号量控制同时发起的请求数量,避免触发API限流,示例如下:
# 全局设置并发数限制,可根据Harvest API限流规则调整,一般设为10-20即可 semaphore = asyncio.Semaphore(10) async def get_dataset(session, url): async with semaphore: async with session.get(url=url, headers=headers, params=params) as resp: if resp.status != 200: # 可增加指数退避重试逻辑 await asyncio.sleep(2) return await get_dataset(session, url) dataset = await resp.json() return dataset['time_entries']
2. 增加异常容忍机制
将asyncio.gather的return_exceptions参数设为True,避免单个请求失败导致整个任务终止,后续可单独处理失败的请求:
dataset = await asyncio.gather(*tasks, return_exceptions=True) # 后续过滤处理异常结果 valid_dataset = [entry for entry in dataset if not isinstance(entry, Exception)]
3. 拆分大查询范围
如果日期跨度超过3个月,建议拆分为多个小的时间段分别查询,避免单次查询压力过大触发服务端超时。
内容的提问来源于stack exchange,提问作者Srichard90
相关产品推荐
相关产品推荐

