python-requests似乎支持將自定義集合作爲要上載的文件的列表/映射。如何將每個文件的自定義標題添加到分段上傳請求中?
這反過來應該允許我添加自定義標題字段,每個文件在一個分段上傳中上傳。
我該怎麼做到這一點?
python-requests似乎支持將自定義集合作爲要上載的文件的列表/映射。如何將每個文件的自定義標題添加到分段上傳請求中?
這反過來應該允許我添加自定義標題字段,每個文件在一個分段上傳中上傳。
我該怎麼做到這一點?
python-requests似乎支持自定義集合作爲要上載的文件的列表/映射。
這反過來應該允許我添加自定義標題字段,每個文件在一個分段上傳中上傳。
沒有。列表/映射中的每個文件必須是文件對象(或內容字符串),文件名和文件對象(或內容)的二元組,或文件名,文件對象(或內容)和文件的三元組類型。其他任何都是非法的。
除非#1640被上游接受,在這種情況下,您只需使用文件名,文件對象(或內容),文件類型和標題字典的4元組。
在這一點上正確的做法可能是使用不同的庫。例如,如果您直接使用urllib3
而不是通過request
包裝器,它會使您想要的操作變得相當容易。你只需要處理所有使用urllib3
而不是requests
的冗餘。
與此同時,您可以針對requests
提交功能請求,並且未來可能會添加更簡單的方法。
但是,如果您需要的功能都是隱藏在屏幕下方,您無法實現,但有點令人沮喪。
看起來乾淨地做事會是一場噩夢。但是這些代碼都非常簡單,我們可以很輕鬆地進入它,所以讓我們這樣做。
看看requests.PreparedRequest.prepare_body
。它期望files
中的每個文件都是文件名,內容或文件對象的元組,以及可選的內容類型。它基本上只讀取任何文件對象以將其轉換爲內容,並將所有內容直接傳遞給urllib3.filepost.encode_multipart_formdata
。所以,除非我們想要替換這個代碼,否則我們需要用這些值中的一個將頭文件走私。讓我們通過(filename, contents, (content_type, headers_dict))
來做到這一點。所以,requests
本身沒有改變。
那它所稱的urllib3.filepost.encode_multipart_formdata
呢?正如你所看到的,如果你爲文件傳遞元組,它會調用一個名爲iter_field_objects
的函數,最終每個函數都會調用urllib3.fields.RequestField.from_tuples
。但是如果你看看from_tuples
替代構造函數,它表示它在那裏處理構造RequestField對象的「舊式」方式,並且正常的構造函數用於「新式」方式,實際上它可以讓你通過頭。
所以,我們所需要做的就是monkeypatch iter_field_objects
,用一種使用新風格的方式取代最後一行,我們應該完成。讓我們嘗試:
import requests
import requests.packages.urllib3
from requests.packages.urllib3.fields import RequestField, guess_content_type
import six
old_iter_field_objects = requests.packages.urllib3.filepost.iter_field_objects
def iter_field_objects(fields):
if isinstance(fields, dict):
i = six.iteritems(fields)
else:
i = iter(fields)
for field in i:
if isinstance(field, RequestField):
yield field
else:
name, value = field
filename = value[0]
data = value[1]
content_type = value[2] if len(value)>2 else guess_content_type(filename)
headers = None
if isinstance(content_type, (tuple, list)):
content_type, headers = content_type
rf = RequestField(name, data, filename, headers)
rf.make_multipart(content_type=content_type)
yield rf
requests.packages.urllib3.filepost.iter_field_objects = iter_field_objects
現在:
>>> files = {'file': ('foo.txt', 'foo\ncontents\n'),
... 'file2': ('bar.txt', 'bar contents', 'text/plain'),
... 'file3': ('baz.txt', 'baz contents', ('text/plain', {'header': 'value'}))}
>>. r = request.Request('POST', 'http://example.com', files=files)
>>> print r.prepare().body
--1ee28922d26146e7a2ee201e5bf22c44
Content-Disposition: form-data; name="file3"; filename="baz.txt"
Content-Type: text/plain
header: value
baz contents
--1ee28922d26146e7a2ee201e5bf22c44
Content-Disposition: form-data; name="file2"; filename="bar.txt"
Content-Type: text/plain
bar contents
--1ee28922d26146e7a2ee201e5bf22c44
Content-Disposition: form-data; name="file"; filename="foo.txt"
Content-Type: text/plain
foo
田田!
請注意,您需要使用相對最新的requests
/urllib3
才能正常工作。我認爲requests
2.0.0就足夠了。
太棒了!我現在可以堅持這一點,並向上遊請求實現一個元組擴展,希望下一個版本支持這個:) –
@qarma:如果你要[添加功能請求](https://github.com/kennethreitz/requests/issues/new),請儘快填寫並在此鏈接。因爲我可能自己編寫一個補丁程序,而且我不想創建一個與您的功能請求重複但沒有連接的請求。 – abarnert
https://github.com/kennethreitz/requests/issues/1639 –