使用Multipart / form-data的POST请求。内容类型不正确

时间:2013-08-07 12:41:57

标签: python urllib python-requests

我们正在尝试使用python编写脚本(使用python-requests a.t.m.)对内容必须为MultipartFormData的站点发出POST请求。 当我们手动执行此POST请求时(通过在网站上填写表单并发布),使用wireshark,这就出现了(简短版本):

Content-Type: multipart/form-data;
Content-Disposition: form-data; name="name"
Data (8 Bytes)
    John Doe

当我们尝试使用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

奇怪的是,数据包的'常规类型'确实是多部分/表单数据,但发送的单个项目(key ='name',value ='John Doe')具有类型application / x-pandoplugin (我想在我的电脑上随机应用)。

这是使用的代码:

response = s.post('http://url.com', files={'name': 'John Doe'})

有没有办法指定单个项目的内容类型,而不是使用headers参数(只更改“整个”数据包的类型)?

我们认为服务器没有正确响应,因为它无法理解我们发送的内容类型。

小更新: 我认为多部分内容的不同部分现在与我在浏览器中执行POST时发送的部分相同,所以这很好。服务器实际上并没有执行我用脚本发送的更改。唯一不同的是不同部分的顺序。

例如,这是我的浏览器发送的内容:

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)

这就是脚本(使用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)

服务器是否可能依赖于部件的顺序?根据{{​​3}},它显然是?如果是这样,是否可以使用请求库明确强制执行订单? 并且在这种情况下使事情变得更糟:文件和文本值混合在一起。

所以迫使订单似乎相当困难。这是我目前的做法:

s.post('http://www.url.com', files=files,data = form_values)

EDIT2: 我在请求插件中进行了修改,以确保部件的顺序与原始请求中的顺序相同。这不能解决问题所以我想我的问题没有直接的解决方案。我会发送邮件给网站的开发者,希望他们能帮助我!

3 个答案:

答案 0 :(得分:8)

您的代码看起来是正确的。

requests.post('http://url.com', files={'name': 'John Doe'})

...并且应该发送'multipart / form-data'帖子。

事实上,我发布了这样的内容:

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

没有想法为什么你会得到那个奇怪的Content-Type标题:

Content-Type: application/x-pandoplugin

我首先要从你的机器上完全删除Pando Web插件,然后再次尝试你的python请求代码。 (或尝试使用其他机器)

答案 1 :(得分:2)

截至今天你可以这样做:

response = s.post('http://url.com', files={'name': (filename, contents, content_type)})

答案 2 :(得分:0)

Python使用系统范围的配置文件来“猜测”文件的mime类型。如果这些插件使用自定义mime类型注册您的文件扩展名,您最终会将其放入。

最安全的方法是使你自己的mime类型猜测适合你正在发送的特定服务器,并且只使用本机python mime类型猜测你想不到的扩展。

你是如何使用我不知道的python请求手动指定内容类型的,但我希望它是可能的。