Сообщить об ошибке.

Объект PreparedRequest модуля requests в Python

Подготовленный объект запроса для отправки на сервер

Всякий раз, когда создается объект ответа сервера Response в результате вызова API или вызова сеанса/сессии, атрибуты запроса (заголовки, кукисы и т.д.) фактически является уже использованными, и их уже нельзя переопределить.

Представим ситуацию, когда приложение работает на потоках, и нужно поставить объекты запросов в очередь. Но как, они же выполняются в момент передачи аргументов в соответствующий метод. Или например и в силу каких то обстоятельств, перед отправкой запроса на сервер, встает острая необходимость проделать дополнительную работу с телом или заголовками (или с чем-то еще) этого запроса.

Такие изменения можно сделать, если предварительно подготовить запрос, т.е. создать объект PreparedRequest перед отправкой его на сервер.

Простой рецепт для этого следующий:

# псевдокод (необходимо определить параметры запроса и т.д.)

from requests import Request, Session
# создаем объект сессии
sess = Session()
# подготавливаем POST запрос
req = Request('POST', url, data=data, headers=headers)
# создаем объект подготовленного запроса
prepped = req.prepare()
# переопределим подготовленное тело запроса.
prepped.body = 'другое тело запроса.'
# удалим 'Content-Type' из подготовленных заголовков.
del prepped.headers['Content-Type']
# отсылаем запрос на сервер
resp = sess.send(prepped,
    stream=stream,
    verify=verify,
    proxies=proxies,
    cert=cert,
    timeout=timeout
)

print(resp.status_code)

Т.к. при подготовке с объектом запроса на сервер ничего не отсылается, то можно немедленно изменить созданный объект PreparedRequest. А затем спокойно отправить его вместе с другими параметрами, которые отправляются в методы requests.* или Session.*.

Однако приведенный выше код потеряет некоторые преимущества наличия сеанса/сессии запросов. В частности, состояние уровня сеанса, такое как файлы cookie, не будет применяться к подготовленному запросу. Чтобы получить объект подготовленного запроса PreparedRequest с этим состоянием, необходимо заменить вызов Request.prepare() вызовом Session.prepare_request(), например:

# псевдокод (необходимо определить параметры запроса и т.д.)

from requests import Request, Session
# создаем объект сессии
sess = Session()
# подготавливаем GET запрос
req = Request('GET',  url, data=data, headers=headers)

# Здесь изменения о которых говориться выше
prepped = sess.prepare_request(req)

# переопределим подготовленное тело запроса.
prepped.body = 'Seriously, send exactly these bytes.'
# Добавим заголовок.
prepped.headers['Keep-Dead'] = 'parrot'
# отсылаем запрос на сервер
resp = s.send(prepped,
    stream=stream,
    verify=verify,
    proxies=proxies,
    cert=cert,
    timeout=timeout
)

print(resp.status_code)

Когда используется подготовленный поток запросов, имейте в виду, что он не принимает во внимание переменные среды. Это может вызвать проблемы, если используется переменная среды для изменения поведения запросов. Например: самоподписанные сертификаты SSL, указанные в REQUESTS_CA_BUNDLE, не будут учитываться. В результате выдается SSL: CERTIFICATE_VERIFY_FAILED.

Можно обойти это поведение, явно объединив настройки среды в свой сеанс:

# псевдокод (необходимо определить параметры запроса и т.д.)

from requests import Request, Session

sess = Session()
req = Request('GET', url)

prepped = sess.prepare_request(req)

# Слияние параметров переменной среды в сеанс/сессию
settings = sess.merge_environment_settings(prepped.url, {}, None, None, None)
resp = sess.send(prepped, **settings)

print(resp.status_code)