По умолчанию, когда отправляется запрос на сервер, тело ответа загружается немедленно. Можно переопределить такое поведение и отложить загрузку тела ответа сервера до тех пор, пока библиотека requests
не получит доступ к атрибуту Response.content
, который управляется аргументом stream
, передаваемый при создании запроса.
tarball_url = 'https://github.com/psf/requests/tarball/master' resp = requests.get(tarball_url, stream=True)
На данный момент загружены только заголовки ответов, и соединение остается открытым, что позволяет сделать загрузку нужного контента условным:
if int(resp.headers['content-length']) < TOO_LONG: content = resp.content ...
Можно дополнительно управлять рабочим процессом с помощью методов Response.iter_content()
и Response.iter_lines()
. Кроме того, можно прочитать не декодированное тело ответа сервера, которое возвращает атрибут Response.raw
(из базового urllib3.HTTPResponse
).
Если установить для аргумента потока stream
значение True
при подготовке запроса или при его выполнении методом requests.get()
, requests.post()
и т.д., то библиотека не сможет освободить соединение обратно в пул, если клиент не прочитает все данные или не вызовет метод Response.close()
. Это может привести к неэффективности подключений.
Если при использовании stream=True
обнаружится, что тело запроса нужно прочитать частично (или вообще не надо читать), то запрос к серверу следует делать в контекстном менеджере with
, чтобы он всегда смог автоматически закрыться:
with requests.get('https://httpbin.org/get', stream=True) as resp: # здесь делаем что-нибудь с ответом.
Библиотека requests
поддерживают потоковую отправку/загрузку контента, которая позволяет отправлять/загружать большие потоки или файлы, не считывая их в память целиком.
Для потоковой передачи или загрузки просто предоставьте файлоподобный объект для тела запроса:
Пример отправки большого файла:
with open('massive-body', 'rb') as fp: requests.post('http://some.url/streamed', data=fp)
Предупреждение. Настоятельно рекомендуется открывать файлы в двоичном режиме 'rb'
. Это связано с тем, что запросы могут попытаться предоставить заголовок Content-Length
, и если это произойдет, то это значение будет установлено на количество байтов в файле. При открытии файла в текстовом режиме могут возникнуть ошибки.
Библиотека requests
также поддерживает фрагментированную передачу контента для исходящих и входящих запросов. Чтобы отправить запрос с фрагментом тела запроса, просто предоставьте генератор (или любой итератор без указания длины) для тела запроса:
def gen(): yield 'hi' yield 'there' requests.post('http://some.url/chunked', data=gen())
Для фрагментированных закодированных ответов лучше всего перебирать данные с помощью Response.iter_content()
. В идеальной ситуации нужно установить для запроса аргумент stream=True
, и в этом случае можно выполнять итерацию по частям, вызывая метод .iter_content()
с аргументом chunk_size=None
. Если нужно установить максимальный размер блока, то можно установить параметр chunk_size
в любое целое число.
Благодаря urllib3
поддержка соединения keep-alive работает на 100% автоматически в течение всего сеанса! Любые запросы, которые делаются в течение сеанса, автоматически повторно используют соответствующее соединение!
Обратите внимание, что соединения освобождаются обратно в пул для повторного использования только после того, как все данные тела были прочитаны. Обязательно установите stream=False
или прочитайте до конца контент, находящийся в Response.content
.