如何在aiohttp异常场景下获取完整请求数据(无需全局变量)
无需全局变量获取aiohttp完整请求信息的替代方案
已知CustomClientRequest可行,这里提供两种无需全局变量、也不用猴子补丁的实现方式,都能在请求异常时拿到包含自动请求头、带查询参数URL的完整请求数据:
1. 继承ClientRequest扩展请求跟踪
直接继承aiohttp.ClientRequest,在预处理阶段完成后把完整请求信息存在请求实例自身的属性里,后续异常发生时直接从请求对象中读取。
import aiohttp from aiohttp.client_reqrep import ClientRequest class TrackedClientRequest(ClientRequest): async def _prepare(self, *args, **kwargs): # 先执行父类的预处理逻辑,生成最终的URL、请求头等数据 await super()._prepare(*args, **kwargs) # 把完整请求信息存在实例属性里 self.prepared_info = { "url": str(self.url), "headers": dict(self.headers), "method": self.method, "request_data": self.data if hasattr(self, "data") else None } # 使用时给ClientSession指定自定义请求类 async def main(): async with aiohttp.ClientSession(request_factory=TrackedClientRequest) as session: try: # 发起一个会失败的请求 async with session.get("https://example.invalid", headers={"X-Custom-Header": "test"}) as resp: await resp.text() except Exception as e: # 从请求实例中获取预处理后的完整信息 # 若异常来自请求预处理阶段,可通过异常上下文拿到请求对象 if hasattr(e.__context__, "request"): req = e.__context__.request print("异常时的完整请求信息:", req.prepared_info) print("异常详情:", str(e))
2. 封装请求方法,绑定信息到异常
不修改ClientRequest类,而是封装session的请求流程:先完成请求预处理,把完整信息附加到后续抛出的异常对象上,异常时直接从异常属性读取。
import aiohttp from aiohttp.client_reqrep import ClientRequest async def tracked_request(session, method, url, **kwargs): # 创建请求对象并完成预处理 req = ClientRequest(method, url, session=session, **kwargs) await req.prepare(session) # 整理完整请求信息 request_info = { "url": str(req.url), "headers": dict(req.headers), "method": req.method } try: # 执行请求 return await session._request(req) except Exception as e: # 把请求信息绑定到异常对象 setattr(e, "request_info", request_info) raise async def main(): async with aiohttp.ClientSession() as session: try: await tracked_request(session, "GET", "https://example.invalid", headers={"X-Custom": "demo"}) except Exception as e: print("异常时的请求信息:", getattr(e, "request_info", "无可用信息")) print("异常:", str(e))
关于TraceConfig失败的原因
TraceConfig的on_request_start钩子触发时,请求可能还没完成预处理(比如session级别的自动请求头还未合并到请求中),如果异常发生在预处理阶段,就拿不到完整的最终请求数据。上面两种方案都是在预处理完成后再执行请求,确保拿到的是最终的请求信息。
内容的提问来源于stack exchange,提问作者duckasaur
相关产品推荐
相关产品推荐

