用python请求压缩请求体?

时间:2015-02-22 08:48:48

标签: python http gzip python-requests

(此问题关于来自网络服务器的gzip - 编码响应的透明解压缩;我知道requests handles that automatically。)< / p>

问题

我试图将文件发布到RESTful Web服务。显然,requests使这很容易做到:

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

在这种情况下,我的文件采用高度可压缩的格式(是的,XML),因此我想确保压缩请求正文。

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

尝试解决方案

我试图让这项工作成功:我首先构建请求并准备它,然后我进入PreparedRequest对象,将body拉出来,通过{{运行它1}},然后把它放回去。 (哦,不要忘记更新gzipContent-Length标题。)

Content-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进行请求正文压缩?

编辑:来自@ sigmavirus24 answer的固定(3)和(5)(这些基本上只是我在简化要发布的代码时忽略的工件它在这里)。

2 个答案:

答案 0 :(得分:6)

  

或者我的做法可能有误?

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

首先,一些事情:

  1. files参数构造multipart/form-data正文。所以你要压缩服务器可能没有任何线索的东西。
  2. Content-EncodingTransfer-Encoding是两个非常不同的东西。你想在这里Transfer-Encoding
  3. 您不需要在NamedTemporaryFile上设置后缀。
  4. 由于您没有明确提及您正在尝试压缩multipart/form-data请求,我将假设您实际上并不想这样做。
  5. 您对session.Request(我认为应该是requests.Request)的来电缺少一种方法,即它应该是:requests.Request('POST', endpoint_url, ...)
  6. 有了这些,请按照以下方式进行操作:

    # 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)
    

    假设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后如何处理内容。

答案 1 :(得分:1)

我有question被标记为完全重复。我关注交易的两端。

来自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");
});

包含更多详细日志记录的gist here。此版本没有任何内置安全性或检查功能。