如何将 Content-disposition header 设置为文件部分的附件?
how to set Content-disposition header as attachment for file part?
我正在使用 Python 请求模块发送包含 form-data 和文件附件的 multi-part HTTP POST 请求。
每个multi-partobject的"Content-disposition"header设置为"form-data",包括文件部分。
我需要 "Content-disposition" header 用于 form-data 部分仍然说 "form-data",但 "Content-disposition" header 用于文件部分必须说 "attachment" 而不是 "form-data".
如何仅将 content-disposition header 更改为 file-part?
我的代码:
#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)
这是 file-part 的 header 在 Python 请求下的样子:
Content-Type: app/xml
Content-Disposition: form-data; name="settings"; filename="settings.xml"
这就是我需要 file-part 的 header 的样子:
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'})}
但这没有效果。我可以指定任何其他自定义 header,它会添加它,但如果我使用该方法,它不会更改 "Content-Disposition" header。
有什么想法吗?
使用工具带:
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})
results in
...--2ba9624051854b6d961bad262a1792fc
Content-Disposition: form-data; name="settings"; filename="settings"
Content-Type: app/xml
<?xml version="1.0" encoding="utf-16"?>...
Question: Set Content-disposition header as attachment for file part?
简短的回答:使用 python-requests
,这是不可能的,现在的实现方式。
Explanation:
class RequestEncodingMixin(object):
...
def _encode_files(files, data):
...
rf = RequestField(name=k, data=fdata, filename=fn, headers=fh)
rf.make_multipart(content_type=ft)
Variable fh
holdes the 4th tuple item passed from
files = {'settings': (filename, io.BytesIO(b'some,data,to,send\nanother,row,to,send\n'),
'app/xml', {'Content-Disposition':'attachment'} )}
The rf.header dict
get updated passing headers=fh
with 'Content-Disposition':...
.
Calling rf.make_multipart(content_type=ft)
, at the next line, only passing the 3trd tuple item.
The method make_multipart
- urllib3/fields.py is defined as
def make_multipart(
self, content_disposition=None, content_type=None, content_location=None
):
self.headers["Content-Disposition"] = content_disposition or u"form-data"
...
which replaces self.headers["Content-Disposition"]
with the default u"form-data"
.
Possible Solutions:
只用urllib3
你可以做到
rf.make_multipart(content_disposition=fh.get("Content-Disposition"), content_type=ft)
向 urllib3
and/or python-requests
提出请求以解决此问题。
给自己打补丁,requests/models.py
或 urlib3/fields
。
Patch: def make_multipart
仅添加默认值 Content-Disposition: form-data
(如果 self.headers
中还没有)。
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
Resulting 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
我正在使用 Python 请求模块发送包含 form-data 和文件附件的 multi-part HTTP POST 请求。
每个multi-partobject的"Content-disposition"header设置为"form-data",包括文件部分。
我需要 "Content-disposition" header 用于 form-data 部分仍然说 "form-data",但 "Content-disposition" header 用于文件部分必须说 "attachment" 而不是 "form-data".
如何仅将 content-disposition header 更改为 file-part?
我的代码:
#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)
这是 file-part 的 header 在 Python 请求下的样子:
Content-Type: app/xml
Content-Disposition: form-data; name="settings"; filename="settings.xml"
这就是我需要 file-part 的 header 的样子:
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'})}
但这没有效果。我可以指定任何其他自定义 header,它会添加它,但如果我使用该方法,它不会更改 "Content-Disposition" header。
有什么想法吗?
使用工具带:
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})
results in
...--2ba9624051854b6d961bad262a1792fc Content-Disposition: form-data; name="settings"; filename="settings" Content-Type: app/xml <?xml version="1.0" encoding="utf-16"?>...
Question: Set Content-disposition header as attachment for file part?
简短的回答:使用 python-requests
,这是不可能的,现在的实现方式。
Explanation:
class RequestEncodingMixin(object): ... def _encode_files(files, data): ... rf = RequestField(name=k, data=fdata, filename=fn, headers=fh) rf.make_multipart(content_type=ft)
Variable
fh
holdes the 4th tuple item passed fromfiles = {'settings': (filename, io.BytesIO(b'some,data,to,send\nanother,row,to,send\n'), 'app/xml', {'Content-Disposition':'attachment'} )}
The
rf.header dict
get updated passingheaders=fh
with'Content-Disposition':...
.
Callingrf.make_multipart(content_type=ft)
, at the next line, only passing the 3trd tuple item.The method
make_multipart
- urllib3/fields.py is defined asdef make_multipart( self, content_disposition=None, content_type=None, content_location=None ): self.headers["Content-Disposition"] = content_disposition or u"form-data" ...
which replaces
self.headers["Content-Disposition"]
with the defaultu"form-data"
.
Possible Solutions:
只用
urllib3
你可以做到rf.make_multipart(content_disposition=fh.get("Content-Disposition"), content_type=ft)
向
urllib3
and/orpython-requests
提出请求以解决此问题。给自己打补丁,
requests/models.py
或urlib3/fields
。
Patch:
def make_multipart
仅添加默认值 Content-Disposition: form-data
(如果 self.headers
中还没有)。
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
Resulting 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