如果可能的话,我更愿意创建自己的“响应流程”,而不是使用任何形式的猴子补丁。我已经检查了请求库的源代码,我们可以使用请求事件钩子系统实现所需的功能。
有一个可行的示例,我们可以对响应执行任何操作。唯一的变化是我们必须为使用该功能使用自己的Session
对象实例。但是!如果我们不想覆盖任何源代码,我们可以进行一行猴子补丁,将默认的Session
类覆盖为默认API调用,并且它将在任何地方像魅力一样工作。
我的解决方案在这里。
import requests
class ResponseVerbose(requests.Response):
extra_header_repr = 'X-Request-Guid'
def __repr__(self):
return '<Response [{}] {}: {}>'.format(
self.status_code,
self.extra_header_repr,
self.headers.get(self.extra_header_repr, 'None')
)
class Session(requests.Session):
def __init__(self):
super().__init__()
self.hooks['response'] = self.build_response
@staticmethod
def build_response(resp, *args, **kwargs):
"""
Let's rebuild the source response into required verbose response object using all fields from the original
FYI: requests.adapters.HTTPAdapter.build_response
"""
response = ResponseVerbose()
response.status_code = resp.status_code
response.headers = resp.headers
response.encoding = resp.encoding
response.raw = resp.raw
response.reason = response.raw.reason
response.url = resp.url
response.cookies = resp.cookies.copy()
response.request = resp.request
response.connection = resp.connection
return response
def main():
url = 'https://stackoverflow.com/'
sess = Session()
print('response using our own session object: {}'.format(sess.get(url)))
import requests.api
requests.api.sessions.Session = Session
print('response using monkey patched global Session class: {}'.format(requests.get(url)))
if __name__ == '__main__':
main()
输出
response using our own session object: <Response [200] X-Request-Guid: 0c446bb5-7c96-495d-a831-061f5e3c2afe>
response using monkey patched global Session class: <Response [200] X-Request-Guid: 1db5aea7-8bc9-496a-addc-1231e8543a89>
使用 Response.__getstate__()
函数的另一个更短的示例
更多信息 https://github.com/psf/requests/blob/master/requests/models.py#L654
从源代码中可以看出,如果响应内容非常大,则不应该对其进行操作,因为它会获取整个 resp.content
以将响应状态转换为状态字典。因此,仅在您知道响应中没有千兆字节时才使用它 :)
这个函数看起来容易得多。
import requests
class ResponseVerbose(requests.Response):
extra_header_repr = 'X-Request-Guid'
def __repr__(self):
return '<Response [{}] {}: {}>'.format(
self.status_code,
self.extra_header_repr,
self.headers.get(self.extra_header_repr, 'None')
)
class Session(requests.Session):
def __init__(self):
super().__init__()
self.hooks['response'] = self.build_response
@staticmethod
def build_response(resp, *args, **kwargs):
"""
Let's rebuild the source response into required verbose response object using all fields from the original
FYI: requests.adapters.HTTPAdapter.build_response
"""
response = ResponseVerbose()
for k, v in resp.__getstate__().items():
setattr(response, k, v)
return response
def main():
url = 'https://stackoverflow.com/'
sess = Session()
print('response using our own session object: {}'.format(sess.get(url)))
import requests.api
requests.api.sessions.Session = Session
print('response using monkey patched global Session class: {}'.format(requests.get(url)))
if __name__ == '__main__':
main()
该解决方案打印出StackOverflow的额外响应头
X-Request-Guid
,仅供示例。我很容易地将此额外头配置为可配置,以展示如何以正确的方式完成此操作。
Response
覆盖__repr__
来猴子补丁requests.Response
。 - heemayl