用python-requests压缩请求主体? [英] Compressing request body with python-requests?

查看:136
本文介绍了用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.

首先,几件事:

  1. files 参数构造一个 multipart/form-data 主体.因此,您正在压缩服务器可能不了解的内容.
  2. Content-Encoding Transfer-Encoding 是两个非常不同的东西.您要在此处 Transfer-Encoding .
  3. 您无需在 NamedTemporaryFile 上设置后缀.
  4. 由于您没有明确提及要压缩 multipart/form-data 请求,因此我假设您实际上并不想这样做.
  5. 您对 session.Request 的调用(我认为应该是 requests.Request )缺少一个方法,即,它应该是: requests.请求("POST",endpoint_url,...)
  1. The files parameter constructs a multipart/form-data body. So you're compressing something that the server potentially has no clue about.
  2. Content-Encoding and Transfer-Encoding are two very different things. You want Transfer-Encoding here.
  3. You don't need to set a suffix on your NamedTemporaryFile.
  4. 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.
  5. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆