用python请求压缩请求体?

Dan*_*ski 7 python gzip http python-requests

(这个问题不是关于来自Web服务器的gzip-encoded 响应的透明解压缩;我知道这requests会自动处理.)

问题

我正在尝试将文件POST到RESTful Web服务.显然,requests这很容易做到:

files = dict(data=(fn, file))
response = session.post(endpoint_url, files=files)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我的文件是一个非常高度可压缩的格式(是的,XML),所以我想确保请求体是压缩的.

服务器声称接受gzip编码(Accept-Encoding: gzip在响应头中),所以我应该能够gzip整个身体请求体,对吧?

试图解决方案

这是我尝试完成这项工作:我首先构建请求并准备它,然后我进入PreparedRequest对象,猛拉出来body,运行它gzip,并把它放回去.(哦,不要忘记更新Content-LengthContent-Encoding标题.)

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)
Run Code Online (Sandbox Code Playgroud)

不幸的是,服务器没有合作并返回500 Internal Server Error.也许它并没有真正接受gzip-encoded请求?

或者我的方法可能有错误?这似乎相当复杂.是否有更简单的方法来执行请求身体压缩python-requests

编辑:固定(3)和(5)来自@ sigmavirus24的答案(这些基本上只是我在简化代码时忽略的工件,在此处发布).

Ian*_*sco 6

或者我的方法可能有错误?

坦白说,我不确定你是如何达到你的方法的,但肯定有一种更简单的方法.

首先,一些事情:

  1. files参数构造一个multipart/form-data主体.所以你正在压缩服务器可能没有任何线索的东西.
  2. Content-Encoding并且Transfer-Encoding是两个非常不同的东西.你想要的Transfer-Encoding.
  3. 您无需在您的上面设置后缀NamedTemporaryFile.
  4. 由于您没有明确提到您正在尝试压缩multipart/form-data请求,我将假设您实际上并不想这样做.
  5. 你对session.Request(我认为应该是requests.Request)的调用缺少一个方法,即它应该是:requests.Request('POST', endpoint_url, ...)

有了这些,这就是我将如何做到这一点:

# 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': gzfile.tell(),
               'Transfer-Encoding': 'gzip'}
    gzfile.seek(0, 0)
    response = session.post(endpoint_url, data=gzfile, 
                            headers=headers)
Run Code Online (Sandbox Code Playgroud)

假设其中file包含xml内容并且您的意思是压缩它,这应该适合您.你可能想设置一个Content-Type标题,例如,你就是这样做的

 headers = {'Content-Length': gzfile.tell(),
            'Content-Type': 'application/xml',  # or 'text/xml'
            'Transfer-Encoding': 'gzip'}
Run Code Online (Sandbox Code Playgroud)

Transfer-Encoding通知的请求仅在运输过程中被压缩的服务器,它应该解压.该Content-Type告诉服务器如何,一旦处理内容Transfer-Encoding已经被处理.