为requests Response扩展自定义方法时触发AttributeError问题求助
如何为requests的Response对象添加自定义校验方法
你遇到的AttributeError: 'Response' object has no attribute 'history',是因为自定义的Response类仅封装了原生requests的Response对象,但未暴露原生对象的属性和方法。requests的Session在处理响应时会访问history等原生Response属性,而你的自定义类未提供这些属性,导致报错。
以下是两种可行的解决方案:
方案1:继承requests原生Response类(推荐)
直接继承requests.Response,自定义类会自动继承原生Response的所有属性和方法,只需添加自定义校验方法即可:
步骤1:定义自定义Response类
import requests class CustomResponse(requests.Response): def validate_ok(self): """校验响应状态码为200且返回结果符合要求""" assert self.status_code == 200, f"预期状态码200,实际为{self.status_code}" json_data = self.json() assert 'result' in json_data, "响应JSON中缺少'result'字段" assert json_data['status'] == 'ok', f"预期状态为'ok',实际为{json_data['status']}" def validate_a(self): """自定义校验方法A""" # 写入你的校验逻辑 pass def validate_c(self): """自定义校验方法C""" # 写入你的校验逻辑 pass
步骤2:重写HTTPAdapter的send方法转换响应
在Adapter中将原生Response转换为自定义Response实例,通过复制属性保留所有原生特性:
class OpenAPIAdapter(requests.adapters.HTTPAdapter): def __init__(self, spec): super().__init__() self.spec = spec def send(self, request, **kwargs): # 获取原生响应 response = super().send(request, **kwargs) # 创建自定义Response实例并复制原生属性 custom_resp = CustomResponse() custom_resp.__dict__.update(response.__dict__) return custom_resp
使用方式
将Adapter挂载到Session后,发起请求即可得到带自定义方法的响应:
session = requests.Session() session.mount("https://your-api-domain.com", OpenAPIAdapter(your_spec)) resp = session.get("/api/endpoint") resp.validate_ok() # 调用自定义校验 resp.validate_a() # 调用其他自定义校验
方案2:封装原生Response并实现属性代理
如果不想继承原生类,可通过__getattr__方法将所有属性访问代理到封装的原生Response对象:
定义封装类
class Response: def __init__(self, response): self.response = response def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): # 代理上下文管理器的exit方法 return self.response.__exit__(exc_type, exc_val, exc_tb) def __getattr__(self, name): # 访问自定义类未定义的属性时,转发给原生Response return getattr(self.response, name) def validate_ok(self): assert self.response.status_code == 200 json_data = self.response.json() assert 'result' in json_data assert json_data['status'] == 'ok' def validate_a(self): # 自定义校验逻辑 pass def validate_c(self): # 自定义校验逻辑 pass
修改Adapter返回封装类
class OpenAPIAdapter(requests.adapters.HTTPAdapter): def __init__(self, spec): super().__init__() self.spec = spec def send(self, request, **kwargs): response = super().send(request, **kwargs) return Response(response)
原代码报错原因
原自定义Response类仅通过self.response保存原生响应,但未实现属性代理逻辑。当requests的Session尝试访问r.history时,自定义类中无该属性,也未将请求转发给原生对象,因此抛出AttributeError。
内容的提问来源于stack exchange,提问作者MG9901
相关产品推荐
相关产品推荐

