Python 请求http库:包含X-Request-ID

Python 请求http库:包含X-Request-ID,python,python-requests,Python,Python Requests,我使用Python中的HTTP客户端库 有时HTTP请求失败,我得到一个状态为500的HTTP响应 这可以是在CI或生产中,我看到如下内容: AssertionError: 200 != 500 : <Response [500]> AssertionError:200!=500 : 这没有多大帮助 如果我能在上面的消息中看到X-Request-ID,那就太好了。在我的环境中,每个HTTP响应都存在这种情况 这意味着请求库的HTTP响应对象应该添加它 我希望repr()看起来像

我使用Python中的HTTP客户端库

有时HTTP请求失败,我得到一个状态为
500
的HTTP响应

这可以是在CI或生产中,我看到如下内容:

AssertionError: 200 != 500 : <Response [500]>
AssertionError:200!=500 : 
这没有多大帮助

如果我能在上面的消息中看到
X-Request-ID
,那就太好了。在我的环境中,每个HTTP响应都存在这种情况

这意味着请求库的HTTP响应对象应该添加它

我希望
repr()
看起来像

因为这不是我的代码,而是请求库的代码,所以我不确定如何实现它


如何将
X-Request-ID
包含在requests-response对象的repr()中?

一种方法是在运行时覆盖requests.models.response.\uuu repr\uu方法(也称为) 正如@heemayl所评论的那样。请注意,这是这种方式的一种变体(我认为是最简单的)

代码00.py:

#/usr/bin/env蟒蛇3
导入系统
导入请求
定义响应报告(自我):
报告标题=(
“X-Request-ID”,
“内容编码”、#@TODO-cfati:仅供演示!!!删除(注释)这一行。
)
repr_parts=[“”)
返回“”。连接(repr_零件)
def主(*argv):
如果argv:
打印(“猴子补丁{0:}…\n.”格式(requests.models.Response))
requests.models.Response.\uuuuu str\uuuuu=requests.models.Response.\uuuu repr\uuuuu35;保留原始的行为
requests.models.Response.\uuu repr\uuu=\uu响应\u repr
url=”https://www.google.com"
打印(“连接到:{0:s}…\n”。格式(url))
r=请求。获取(url)
打印(“str(响应):{0:s}”。格式(str(r)))
打印(“repr(响应):{0:s}”。格式(repr(r)))
如果名称=“\uuuuu main\uuuuuuuu”:
打印(“Python{0:s}{1:d}位在{2:s}\n.format(“.join(sys.version.split(“\n”)中的项的item.strip()),如果sys.maxsize>0x100000000,则为64,否则为32,sys.platform))
main(*sys.argv[1:])
打印(“\n完成”)
输出

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q059193447]>“e:\Work\Dev\VEnvs\py\u 064\u 03.07.03\u test0\Scripts\python.exe”code00.py
Python 3.7.3(v3.7.3:ef4ec6ed12,2019年3月25日,22:22:05)[MSC v.1916 64位(AMD64)]win32上的64位
连接到:https://www.google.com ...
str(答复):
报告员(答复):
完成。
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q059193447]>“e:\Work\Dev\VEnvs\py\u 064\u 03.07.03\u test0\Scripts\python.exe”code00.py dummy\u arg\u to\u trigger\u monkey\u补丁
Python 3.7.3(v3.7.3:ef4ec6ed12,2019年3月25日,22:22:05)[MSC v.1916 64位(AMD64)]win32上的64位
猴子补丁。。。
连接到:https://www.google.com ...
str(答复):
报告员(答复):
完成。

如果可以的话,我更愿意创建自己的“响应流”,而不是使用任何类型的响应流。我已经检查了请求库的来源,我们很乐意去那里!我们可以使用来实现所需的功能

有一个工作示例,我们可以对响应执行任何操作。唯一的变化是我们必须使用自己的
会话
对象实例来使用该功能。但是!如果我们不想覆盖任何源代码,我们可以执行一行Monkey补丁,覆盖默认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()
例如,该解决方案打印StackOverflow的额外响应头
X-Request-Guid


两个选项:1.分叉并创建您自己的副本2.Monkeypatch
请求。响应
使用您自己的
响应
副本覆盖
\uuuuuu repr\uuuu
您是否尝试使用类似SENTRY&RAVEN(生产)的东西-看看它捕捉到了什么?或者用断点在TEST ENV中重新创建错误?@Ohadtheld AFAIK sentry是一项商业服务。如果可能的话,我更喜欢开源解决方案。我到目前为止还没有尝试sentry。不错。不幸的是
build\u response()
仍然很长(例如复制cookie)。也许请求库的作者会允许pull请求使更改响应类变得更简单?为什么不呢,传递响应和请求类可能是一个很好的功能。但现在我不相信:)作为一个快速解决方案,我觉得它看起来很棒:)@guettli添加了一个更简单的解决方案,使用神奇的方法将响应状态转储到state dict.看起来更干净:)我仍然认为更改响应类应该更容易。也许请求库的作者会允许pull请求使更改响应类更简单?为什么不呢,您可以尝试与作者交谈:)
# 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>
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()