Всякий раз, когда создается объект ответа сервера 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)