【问题标题】:Why can response.content be read twice and can't be decoded to json为什么response.content可以读取两次,不能解码成json
【发布时间】:2015-08-26 12:08:57
【问题描述】:

我今天发现了一个奇怪的行为。 我通过 python 请求库在谷歌云消息传递中发送了一条消息。 然后我尝试像这样解码对json的响应:

response = requests.post(Message_Broker.host, data=json.dumps(payload), headers=headers)
response_results = json.loads(response.content)["results"]

由于解码错误而崩溃:

response_results = json.loads(response.content)["results"]
  File "/usr/local/lib/python2.7/dist-packages/simplejson/__init__.py", line 505, in loads
    return _default_decoder.decode(s)
  File "/usr/local/lib/python2.7/dist-packages/simplejson/decoder.py", line 370, in decode
    obj, end = self.raw_decode(s)
  File "/usr/local/lib/python2.7/dist-packages/simplejson/decoder.py", line 400, in raw_decode
    return self.scan_once(s, idx=_w(s, idx).end())
JSONDecodeError: Expecting value: line 1 column 1 (char 0)

这发生在我的生产系统上,所以我添加了一些调试日志来了解响应的实际内容是这样的:

        logger.info("GCM-Response: " + str(response))
        logger.info("GCM-Response: " + response.content)
        logger.info("GCM-Response: " + str(response.headers))

现在发生了实际的奇怪行为。它已正确记录并且不再抛出解码错误。

谁能解释一下这种行为?

我还检查了 response.content 实际上是什么:

@property
    def content(self):
        """Content of the response, in bytes."""

        if self._content is False:
            # Read the contents.
            try:
                if self._content_consumed:
                    raise RuntimeError(
                        'The content for this response was already consumed')

                if self.status_code == 0:
                    self._content = None
                else:
                    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()

            except AttributeError:
                self._content = None

        self._content_consumed = True
        # don't need to release the connection; that's been handled by urllib3
        # since we exhausted the data.
        return self._content

它是requests 模型的一部分。不是实际属性,但可以通过 @property 装饰器访问。 据我了解,第一次为日志读取内容时,_content_consumed 标志设置为 True。因此第二次,当我阅读它以进行 json 解码时,它实际上应该引发运行时错误。

是否有解释,我在浏览请求文档时没有找到?

【问题讨论】:

  • response.json() 是否为您提供所需的 json?
  • 我还没有尝试过,但我想知道我询问的行为。
  • 使用Requests读取json数据的正确方法是response.json()。首先尝试代替您的json.loads,看看它是否可以解决您的问题。

标签: python json python-requests decoding


【解决方案1】:

因此,当我第二次读取它以进行 json 解码时,它实际上应该引发运行时错误。

不,它不会引发RuntimeError。当您第一次访问response.content 时,它会将实际数据缓存到self._content。在第二次(第三次、第四次等)访问时,if self._content is False: 是虚假的,因此您将获得缓存在 self._content 中的内容。

if self._content_consumed: 检查很可能是内部断言,以发现多次从套接字读取数据的尝试(这显然是一个错误)。


它无法解码为 JSON,因为您在响应正文中未收到 JSON 或收到空正文。可能是 500 响应,也可能是 429。没有看到实际响应就不可能说出来。

【讨论】:

    猜你喜欢
    • 2014-03-25
    • 2017-09-20
    • 2018-10-13
    • 2019-02-11
    • 1970-01-01
    • 1970-01-01
    • 2021-10-22
    • 1970-01-01
    • 2019-02-05
    相关资源
    最近更新 更多