Python 带有 Multipart/form-data 的 POST 请求。内容类型不正确
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18103686/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
POST request with Multipart/form-data. Content-type not correct
提问by HaS
We're trying to write a script with python (using python-requests a.t.m.) to do a POST request to a site where the content has to be MultipartFormData. When we do this POST request manually (by filling in the form on the site and post), using wireshark, this came up (short version):
我们正在尝试使用 python(使用 python-requests atm)编写一个脚本,以向内容必须是 MultipartFormData 的站点发出 POST 请求。当我们使用wireshark手动执行此POST请求(通过填写网站上的表格并发布)时,出现了(简短版本):
Content-Type: multipart/form-data;
Content-Disposition: form-data; name="name"
Data (8 Bytes)
John Doe
When we try to use the python-requests library for achieving the same result, this is sent:
当我们尝试使用 python-requests 库来实现相同的结果时,会发送:
Content-Type: application/x-pandoplugin
Content-Disposition: form-data; name="name"; filename="name"\r\n
Media type: application/x-pandoplugin (12 Bytes)
//and then in this piece is what we posted://
John Doe
The weird thing is that the 'general type' of the packet indeed is multipart/form-data, but the individual item sent (key = 'name', value= 'John Doe') has type application/x-pandoplugin (a random application on my pc I guess).
奇怪的是,数据包的“通用类型”确实是 multipart/form-data,但发送的单个项目(key = 'name', value = 'John Doe')的类型为 application/x-pandoplugin(随机我猜我的电脑上的应用程序)。
This is the code used:
这是使用的代码:
response = s.post('http://url.com', files={'name': 'John Doe'})
Is there a way to specify the content-type of the individual items instead of using the headers argument (which only changes the type of the 'whole' packet)?
有没有办法指定单个项目的内容类型而不是使用 headers 参数(它只会更改“整个”数据包的类型)?
We think the server doesn't respond correctly due to the fact that it can't understand the content-type we send it.
我们认为服务器没有正确响应,因为它无法理解我们发送的内容类型。
Little update:I think the different parts of the multipart content are now identical to the ones sent if I do the POST in the browser, so that's good. Still the server doesn't actually do the changes I send it with the script. The only thing that still is different is the order of the different parts.
小更新:我认为多部分内容的不同部分现在与我在浏览器中执行 POST 时发送的部分相同,所以很好。服务器实际上并没有执行我随脚本发送的更改。唯一不同的是不同部分的顺序。
For example this is what my browser sends:
例如,这是我的浏览器发送的内容:
Boundary: \r\n------WebKitFormBoundary3eXDYO1lG8Pgxjwj\r\n
Encapsulated multipart part: (text/plain)
Content-Disposition: form-data; name="file"; filename="ex.txt"\r\n
Content-Type: text/plain\r\n\r\n
Line-based text data: text/plain
lore ipsum blabbla
Boundary: \r\n------WebKitFormBoundary3eXDYO1lG8Pgxjwj\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="seq"\r\n\r\n
Data (2 bytes)
Boundary: \r\n------WebKitFormBoundary3eXDYO1lG8Pgxjwj\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="name"\r\n\r\n
Data (2 bytes)
And this is what the script (using python-requests) sends:
这就是脚本(使用 python-requests)发送的内容:
Boundary: \r\n------WebKitFormBoundary3eXDYO1lG8Pgxjwj\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="name"\r\n\r\n
Data (2 bytes)
Boundary: \r\n------WebKitFormBoundary3eXDYO1lG8Pgxjwj\r\n
Encapsulated multipart part: (text/plain)
Content-Disposition: form-data; name="file"; filename="ex.txt"\r\n
Content-Type: text/plain\r\n\r\n
Line-based text data: text/plain
lore ipsum blabbla
Boundary: \r\n------WebKitFormBoundary3eXDYO1lG8Pgxjwj\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="seq"\r\n\r\n
Data (2 bytes)
Could it be possible that the server counts on the order of the parts? According to Multipart upload form: Is order guaranteed?, it apparently is? And if so, is it possible to explicitly force an order using the requests library? And to make things worse in that case: There is a mixture of a file and just text values.
服务器是否有可能根据零件的顺序进行计数?根据分段上传形式:订单有保证吗?,这显然是?如果是这样,是否可以使用 requests 库明确强制执行订单?在这种情况下更糟糕的是:文件和文本值混合在一起。
So forcing an order seems rather difficult. This is the current way I do it:
所以强制执行命令似乎相当困难。这是我目前的做法:
s.post('http://www.url.com', files=files,data = form_values)
EDIT2:I did a modification in the requests plugin to make sure the order of the parts is the same as in the original request. This doesn't fix the problem so I guess there is no straightforward solution for my problem. I'll send a mail to the devs of the site and hope they can help me!
EDIT2:我对请求插件进行了修改,以确保部件的顺序与原始请求中的顺序相同。这并不能解决问题,所以我想我的问题没有简单的解决方案。我会发邮件给网站的开发者,希望他们能帮助我!
回答by Corey Goldberg
your code looks correct.
你的代码看起来是正确的。
requests.post('http://url.com', files={'name': 'John Doe'})
... and should send a 'multipart/form-data' Post.
...并且应该发送一个“multipart/form-data”帖子。
and indeed, I get something like this posted:
事实上,我收到了这样的帖子:
Accept-Encoding: gzip, deflate, compress
Connection: close
Accept: */*
Content-Length: 188
Content-Type: multipart/form-data; boundary=032a1ab685934650abbe059cb45d6ff3
User-Agent: python-requests/1.2.3 CPython/2.7.4 Linux/3.8.0-27-generic
--032a1ab685934650abbe059cb45d6ff3
Content-Disposition: form-data; name="name"; filename="name"
Content-Type: application/octet-stream
John Doe
--032a1ab685934650abbe059cb45d6ff3--
I have noidea why you'd get that weird Content-Type header:
我不知道为什么你会得到那个奇怪的 Content-Type 标题:
Content-Type: application/x-pandoplugin
I would begin by removing Pando Web Plugin from your machine completely, and then try your python-requests code again. (or try from a different machine)
我会首先从你的机器上完全删除 Pando Web Plugin,然后再次尝试你的 python-requests 代码。(或从不同的机器尝试)
回答by Dobes Vandermeer
Python uses a system-wide configuration file to "guess" the mime-type of a file. If those plugins are registering your file extension with their custom mime-type you'll end up putting that in instead.
Python 使用系统范围的配置文件来“猜测”文件的 MIME 类型。如果这些插件使用它们的自定义 mime 类型注册您的文件扩展名,您最终会改为将其放入。
The safest approach is make your own mime type guessing that suits the particular server you're sending do, and only use the native python mime type guessing for extensions you didn't think of.
最安全的方法是进行适合您发送的特定服务器的自己的 mime 类型猜测,并且仅对您没有想到的扩展使用本机 python mime 类型猜测。
How exactly you specify the content-type manually with python-requests I don't know, but I expect it should be possible.
我不知道如何使用 python-requests 手动指定内容类型,但我希望它应该是可能的。
回答by pguardiario
As of today you can do:
截至今天,您可以执行以下操作:
response = s.post('http://url.com', files={'name': (filename, contents, content_type)})