Requests报”requests.exceptions.StreamConsumedError: Response body was already consumed “的原因以及解决办法

  • Post category:Python

Requests报”requests.exceptions.StreamConsumedError: Response body was already consumed “的原因

Requests库是Python中的一个第三方库,用于发送HTTP/1.1请求。这个报错的原因主要是因为请求的响应内容在处理过程中被多个模块或者函数读取了多次,也就是说响应内容已经被读取并消耗了多次导致的。

在HTTP/1.1中,响应是一个可迭代对象,并且响应数据是以流的形式发送。因此,如果有多个函数同时读取响应内容,就很容易出现循环读取已经消耗的内容,导致出现该异常。

解决办法

解决这种异常情况的办法主要有以下几种:

1. 使用contextlib.contextmanager

使用contextmanager可以帮助我们在不同的上下文中隔离请求和相应可迭代对象。

import contextlib
import requests

@contextlib.contextmanager
def response_context(url):
    resp = requests.get(url)
    try:
        yield resp
    finally:
        resp.close()

url = 'https://www.example.com'
with response_context(url) as resp:
    print(resp.status_code)

这种方法的好处是,不仅可以有效避免多个函数读取响应内容的问题,而且在使用完毕后可以自动关闭响应,释放资源。

2. 使用Response.iter_content方法

iter_content()方法可以迭代响应内容的每个块,从而可以避免一次性读取所有响应内容。

import requests

url = 'https://www.example.com'
resp = requests.get(url, stream=True)
for block in resp.iter_content(1024):
    print(block)

需要注意的是,获取响应时需要将stream标志设置为True,否则iter_content()就会一次性读取所有响应内容,而iter_content()则可以通过每次读取响应的一部分,从而避免将内容全部读取到内存中。

3. 有效消耗响应流

在使用响应内容后,可以通过调用Response.content或Response.text等方法,将响应流全部消耗掉,从而避免响应内容被多次读取。

import requests

url = 'https://www.example.com'
resp = requests.get(url)
resp.content
print(resp.status_code)

注意:只能将响应流消耗一次。如果已经调用过某个方法消耗完毕,再次调用该方法就会造成该异常。

4. 避免多次执行同一次请求

为了避免请求执行多次,我们可以缓存请求结果。使用requests内置的缓存机制,获取缓存内容时不会对服务端产生额外的负担。

import requests
from requests_cache import CachedSession

session = CachedSession()
url = 'https://www.example.com'
resp = session.get(url)
print(resp.status_code)

以上是Requests库报”requests.exceptions.StreamConsumedError: Response body was already consumed “的原因以及解决办法的完整攻略。