用python请求压缩请求体



(这个问题不是关于从web服务器透明解压缩gzip编码的响应的问题;我知道requests会自动处理这个问题。)

问题

我正在尝试将文件POST到RESTful web服务。显然,requests使这项工作变得非常容易:

files = dict(data=(fn, file))
response = session.post(endpoint_url, files=files)

在这种情况下,我的文件是一种非常可压缩的格式(是的,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)

不幸的是,服务器不配合并返回500 Internal Server Error。也许它真的不接受gzip编码的请求?

或者我的方法可能有错误?这看起来相当复杂。有没有一种更简单的方法可以用python-requests进行请求身体压缩?

编辑:修复了@sigmavirus24答案中的(3)和(5)(这些基本上只是我在简化代码以将其发布到此处时忽略的工件)。

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

坦率地说,我不确定你是如何得出这种方法的,但肯定有一种更简单的方法。

首先,几件事:

  1. CCD_ 13参数构造了一个CCD_。因此,您正在压缩服务器可能不知道的内容
  2. CCD_ 15和CCD_。您需要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': str(gzfile.tell()),
               'Transfer-Encoding': 'gzip'}
    gzfile.seek(0, 0)
    response = session.post(endpoint_url, data=gzfile, 
                            headers=headers)

假设file中有xml内容,并且您的意思只是压缩它,这应该对您有效。您可能想要设置一个Content-Type标头,例如,您只需要进行

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

Transfer-Encoding告诉服务器请求只在传输过程中被压缩,它应该对其进行解压缩。Content-Type告诉服务器一旦处理了Transfer-Encoding,如何处理内容。

我有一个问题被标记为完全重复。我对交易的两端都很关心。

sigmavirus24中的代码不是直接的剪切粘贴修复,但它是这个版本的灵感来源。

以下是我的解决方案的结果:

从python端发送

import json
import requests
import StringIO
import gzip
url = "http://localhost:3000"
headers = {"Content-Type":"application/octet-stream"}
data = [{"key": 1,"otherKey": "2"},
        {"key": 3,"otherKey": "4"}]
payload = json.dumps(data)
out = StringIO.StringIO()
with gzip.GzipFile(fileobj=out, mode="w") as f:
  f.write(json.dumps(data))
out.getvalue()
r = requests.post(url+"/zipped", data=out.getvalue(), headers=headers)

在快递端收货

var zlib = require("zlib");
var rawParser = bodyParser.raw({type: '*/*'});
app.post('/zipped', rawParser, function(req, res) {
    zlib.gunzip(req.body, function(err, buf) {
        if(err){
            console.log("err:", err );
        } else{
            console.log("in the inflate callback:",
                        buf,
                        "to string:", buf.toString("utf8") );
        }
    });
    res.status(200).send("I'm in ur zipped route");
});

这里有一个要点,包括更详细的日志记录。这个版本也没有任何内置的安全或检查功能。

最新更新