我使用 requests Python 中的 HTTP 客户端库。
有时 HTTP 请求失败,我会收到状态为 500
的 HTTP 响应.
这可以在 CI 或生产中,我看到这样的东西:
AssertionError: 200 != 500 : <Response [500]>
这没什么帮助。
如果我能看到 X-Request-ID
就好了在上面的消息中。在我的环境中,每个 HTTP 响应都存在。
这意味着请求库的 HTTP 响应对象应该添加它。
我想要 repr()
看起来像<Response [500] XejfkmxcPfhM3dqhY2HJgQAAAAM>
因为这不是我的代码,而是请求库的代码,所以我不确定如何实现它。
如何包含 X-Request-ID
在请求响应对象的 repr() 中?
最佳答案
如果我能做到,我宁愿创建自己的“响应流”,而不是使用任何类型的 monkey patching .我已经检查了请求库的来源,我们很高兴去那里!我们可以使用 requests Event Hooks system 实现所需的功能.
有一个工作示例,我们可以对响应执行任何操作。唯一的变化是我们必须使用我们自己的 Session
对象实例来使用该功能。但!如果我们不想覆盖任何源代码,我们可以做一个 linemonkey-patch,为默认的 api 调用覆盖默认的 Session
类,它会像魅力一样在任何地方工作。
我的解决方案在这里
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()
输出
# python test123.py
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
As I see from the source code, you shouldn't do it for very large content responses since it fetches the whole
resp.content
to be able to convert the response state into a state dict. So use it only if you know that there are not gigabytes in responses :)
这个函数看起来简单多了。
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()
The solution prints StackOverflow's extra response header
X-Request-Guid
just for example. This extra header I did easily configurable just to show how it could be done in the right way.
关于python - 请求 http 库 : include X-Request-ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59193447/