用python-requests压缩请求主体? [英] Compressing request body with python-requests?
问题描述
(此问题不是不是,是关于从Web服务器对 gzip
编码的响应进行透明解压缩的;我知道
(This question is not about transparent decompression of gzip
-encoded responses from a web server; I know that requests
handles that automatically.)
我正在尝试将文件发布到RESTful Web服务.显然, requests
使此操作变得很容易:
I'm trying to POST a file to a RESTful web service. Obviously, requests
makes this pretty easy to do:
files = dict(data=(fn, file))
response = session.post(endpoint_url, files=files)
在这种情况下,我的文件采用的是高度可压缩的格式(是,XML),因此,我想确保 request 正文已压缩.
In this case, my file is in a really highly-compressible format (yep, XML) so I'd like to make sure that the request body is compressed.
服务器声称接受gzip编码(响应头中为 Accept-Encoding:gzip
),所以我应该能够对整个请求体进行gzip压缩,对吧?
The server claims to accept gzip encoding (Accept-Encoding: gzip
in response headers), so I should be able to gzip the whole body request body, right?
这是我要完成这项工作的尝试:首先构造请求并准备它,然后进入 PreparedRequest
对象,取出 body
,将其运行 gzip
,然后放回去.(哦,别忘了更新 Content-Length
和 Content-Encoding
标头.)
Here's my attempt to make this work: I first construct the request and prepare it, then I go into the PreparedRequest
object, yank out the body
, run it through gzip
, and put it back. (Oh, and don't forget to update the Content-Length
and Content-Encoding
headers.)
files = dict(data=(fn, file))
request = request.Request('POST',endpoint_url, files=files)
prepped = session.prepare_request(request)
with NamedTemporaryFile(delete=True) as gzfile:
gzip.GzipFile(fileobj=gzfile, mode="wb").write(prepped.body)
prepped.headers['Content-Length'] = gzfile.tell()
prepped.headers['Content-Encoding'] = 'gzip'
gzfile.seek(0,0)
prepped.body = gzfile.read()
response = session.send(prepped)
不幸的是,服务器未合作,并返回 500 Internal Server Error
.也许它不是真的接受 gzip
编码的请求?
Unfortunately, the server is not cooperating and returns 500 Internal Server Error
. Perhaps it doesn't really accept gzip
-encoded requests?
也许我的方法有误?似乎有点令人费解.有没有一种更简单的方法可以通过 python-requests
进行请求主体压缩?
Or perhaps there is a mistake in my approach? It seems rather convoluted. Is there an easier way to do request body compression with python-requests
?
编辑:修复了@ sigmavirus24的 answer 中的(3)和(5)(基本上是只是我在简化代码以将其发布到此处时忽略的工件.
Fixed (3) and (5) from @sigmavirus24's answer (these were basically just artifacts I'd overlooked in simplifying the code to post it here).
推荐答案
也许我的方法有误?
Or perhaps there is a mistake in my approach?
坦率地说,我不确定您是如何做到这一点的,但是肯定有一种更简单的方法.
I'm unsure how you arrived at your approach, frankly, but there's certainly a simpler way of doing this.
首先,几件事:
-
files
参数构造一个multipart/form-data
主体.因此,您正在压缩服务器可能不了解的内容. -
Content-Encoding
和Transfer-Encoding
是两个非常不同的东西.您要在此处Transfer-Encoding
. - 您无需在
NamedTemporaryFile
上设置后缀. - 由于您没有明确提及要压缩
multipart/form-data
请求,因此我假设您实际上并不想这样做. - 您对
session.Request
的调用(我认为应该是requests.Request
)缺少一个方法,即,它应该是:requests.请求("POST",endpoint_url,...)
- The
files
parameter constructs amultipart/form-data
body. So you're compressing something that the server potentially has no clue about. Content-Encoding
andTransfer-Encoding
are two very different things. You wantTransfer-Encoding
here.- You don't need to set a suffix on your
NamedTemporaryFile
. - Since you didn't explicitly mention that you're trying to compress a
multipart/form-data
request, I'm going to assume that you don't actually want to do that. - Your call to
session.Request
(which I assume should be,requests.Request
) is missing a method, i.e., it should be:requests.Request('POST', endpoint_url, ...)
在没有这些干扰的情况下,这是我的处理方式:
With those out of the way, here's how I would do this:
# Assuming `file` is a file-like obj
with NamedTemporaryFile(delete=True) as gzfile:
gzip.GzipFile(fileobj=gzfile, mode="wb").write(file.read())
headers = {'Content-Length': str(gzfile.tell()),
'Transfer-Encoding': 'gzip'}
gzfile.seek(0, 0)
response = session.post(endpoint_url, data=gzfile,
headers=headers)
假设 file
中包含 xml
内容,并且您只是想压缩它,那么这应该对您有用.您可能想要设置 Content-Type
标头,例如,您只需要这样做
Assuming that file
has the xml
content in it and all you meant was to compress it, this should work for you. You probably want to set a Content-Type
header though, for example, you'd just do
headers = {'Content-Length': gzfile.tell(),
'Content-Type': 'application/xml', # or 'text/xml'
'Transfer-Encoding': 'gzip'}
Transfer-Encoding
告诉服务器该请求仅在传输过程中被压缩,因此应将其解压缩. Content-Type
告诉服务器一旦处理了 Transfer-Encoding
后如何处理内容.
The Transfer-Encoding
tells the server that the request is being compressed only in transit and it should uncompress it. The Content-Type
tells the server how to handle the content once the Transfer-Encoding
has been handled.
这篇关于用python-requests压缩请求主体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!