【问题标题】:how to set Content-disposition header as attachment for file part?如何将 Content-disposition 标头设置为文件部分的附件?
【发布时间】:2019-12-29 20:27:41
【问题描述】:

我正在使用 Python 请求模块发送包含表单数据和文件附件的多部分 HTTP POST 请求。

每个多部分对象的“Content-disposition”标头设置为“form-data”,包括文件部分。

我需要表单数据部分的“Content-disposition”标头仍然显示“form-data”,但文件部分的“Content-disposition”标头必须显示“附件”而不是“表单数据” ”。

如何仅更改文件部分的内容处置标头?

我的代码:

#Python 3.7.3 (default, Apr 24 2019, 13:20:13) [MSC v.1915 32 bit (Intel)]
import requests

#USER PARAMETERS
user_name = 'user_account'
password = 'user_password'
token = '45Hf4xGhj'

#REQUESTS PARAMETERS
url = '192.168.0.2'
headers = {'content-type': 'multi-part/form-data'}
data = {'Username':user_name, 'Password':password, 'Token':token}
files = {'settings': ('settings.xml', open('settings.xml', 'rb'), 'app/xml')}

#POST
response = requests.post(url, headers=headers, data=data, files=files)

这是文件部分的标头与 Python 请求的样子:

Content-Type: app/xml
Content-Disposition: form-data; name="settings"; filename="settings.xml"

这就是我需要的文件部分的标题:

Content-Type: app/xml
Content-Disposition: attachment; name="settings"; filename="settings.xml"

我还尝试通过在文件中添加 header 参数来更改 header:

files = {'settings': ('settings.xml', open('settings.xml', 'rb'),
         'app/xml', {'Content-Disposition':'attachment'})}

但这没有任何效果。我可以指定任何其他自定义标头,它会添加它,但如果我使用该方法,它不会更改“Content-Disposition”标头。

有什么想法吗?


使用工具带:

m = MultipartEncoder( fields={'Username': user_name, 
                              'Password': password, 
                              'Token': token, 
                    'settings': ('settings', open('settings.xml', 'rb'), 
                                 'app/xml', 
                                {'Content-Disposition':'attachment'}
                                )
                             } 
                    ) 

r = requests.post('http://httpbin.org/post', 
                   data=m, 
                   headers={'Content-Type': m.content_type}) 

结果

...--2ba9624051854b6d961bad262a1792fc 
Content-Disposition: form-data; name="settings"; filename="settings"
Content-Type: app/xml 
<?xml version="1.0" encoding="utf-16"?>...

【问题讨论】:

  • @stovfl 谢谢,我尝试了工具带但没有运气。它仍然不会将“Content-Disposition:form-data”标头更改为“Content-Disposition:附件”。同样,如果我选择任何其他标题名称,它会将该标题添加到文件部分的标题中,但不会更改“Content-Disposition”。
  • 也许这个答案How to send a “multipart/form-data” with requests in python? 可以提供帮助。 注意第二条注释“不设置 Content-Type 标头可确保请求将其设置为正确的值”

标签: python python-requests content-disposition


【解决方案1】:

问题:将 Content-disposition 标头设置为文件部分的附件?

简短的回答:使用python-requests,这是不可能的,它现在的实现方式。

解释

requests/models.py

class RequestEncodingMixin(object):
    ...
    def _encode_files(files, data):
        ...
        rf = RequestField(name=k, data=fdata, filename=fn, headers=fh)
        rf.make_multipart(content_type=ft)

变量fh 保存着第4个元组项从

files = {'settings': (filename, io.BytesIO(b'some,data,to,send\nanother,row,to,send\n'),
         'app/xml', {'Content-Disposition':'attachment'} )}

rf.header dict 得到更新,通过 headers=fh'Content-Disposition':...
在下一行调用rf.make_multipart(content_type=ft),只传递了第三个元组项。

方法make_multipart - urllib3/fields.py定义为

def make_multipart(
    self, content_disposition=None, content_type=None, content_location=None
):
    self.headers["Content-Disposition"] = content_disposition or u"form-data"
    ...

self.headers["Content-Disposition"] 替换为默认的u"form-data"


可能的解决方案

  1. 只使用urllib3 你可以这样做

    rf.make_multipart(content_disposition=fh.get("Content-Disposition"), content_type=ft)
    
  2. urllib3 和/或python-requests 提交请求以解决此问题。

  3. 给自己打补丁,requests/models.pyurlib3/fields


补丁def make_multipart

如果self.headers 中还没有,则仅添加默认的Content-Disposition: form-data

from urllib3 import fields

def make_multipart(
        self, content_disposition=None, content_type=None, content_location=None
    ):
        if self.headers.get("Content-Disposition") is None:
            self.headers["Content-Disposition"] = content_disposition or u"form-data"

        self.headers["Content-Disposition"] += u"; ".join(
            [
                u"",
                self._render_parts(
                    ((u"name", self._name), (u"filename", self._filename))
                ),
            ]
        )
        self.headers["Content-Type"] = content_type
        self.headers["Content-Location"] = content_location

fields.RequestField.make_multipart = make_multipart

生成的多部分

--e96a4935b8d5b2355f1da3070faa4b28
Content-Disposition: attachment; name="settings"; filename="settings.xml"
Content-Type: app/xml

some,data,to,send
another,row,to,send

--e96a4935b8d5b2355f1da3070faa4b28--

使用 Python 测试:3.5 - urllib3:1.23 - 请求:2.19.1

【讨论】:

    猜你喜欢
    • 2011-04-27
    • 1970-01-01
    • 1970-01-01
    • 2016-08-25
    • 2013-09-09
    • 1970-01-01
    • 2015-01-29
    • 1970-01-01
    • 2012-08-03
    相关资源
    最近更新 更多