我正在尝试使用 Python 的请求库向 Amazon S3 端点发布请求。该请求属于 multipart/form-data 种类,因为它包括实际文件的 POST。
我正在处理的 API 指定的一项要求是file
参数必须最后发布。由于 Requests 使用字典来发布多部分/表单数据,并且由于字典不遵循指定的顺序,因此我将其转换为名为payload
. 在发布之前它看起来像这样:
{'content-type': 'text/plain',
'success_action_redirect': 'https://ian.test.instructure.com/api/v1/files/30652543/create_success?uuid=<opaque_string>',
'Signature': '<opaque_string>',
'Filename': '',
'acl': 'private',
'Policy': '<opaque_string>',
'key': 'account_95298/attachments/30652543/log.txt',
'AWSAccessKeyId': '<opaque_string>',
'file': '@log.txt'}
这就是我发布它的方式:
r = requests.post("https://instructure-uploads.s3.amazonaws.com/", files = payload)
响应是 500 错误,所以我真的不确定这里有什么问题。我只是猜测这与我在 Requests 中使用 OrderedDict 有关——我找不到任何说明 Requests 支持或不支持 OrderedDicts 的文档。这可能是完全不同的东西。
是否还有其他任何会导致请求失败的问题?如果需要,我可以提供更多细节。
好的,更新,基于 Martijn Pieters 之前的评论:
我更改了引用 log.txt 文件的方式,将其添加到已创建的upload_data
字典中,如下所示:
upload_data['file'] = open("log.txt")
打印结果字典我得到这个:
{'AWSAccessKeyId': '<opaque_string>',
'key': '<opaque_string>',
'Policy': '<opaque_string>',
'content-type': 'text/plain',
'success_action_redirect': 'https://ian.test.instructure.com/api/v1/files/30652688/create_success?uuid=<opaque_string>',
'Signature': '<opaque_string>',
'acl': 'private',
'Filename': '',
'file': <_io.TextIOWrapper name='log.txt' mode='r' encoding='UTF-8'>}
键的值file
看起来正确吗?
当我将它发布到 RequestBin 时,我得到了这个,它看起来与 Martin 的示例非常相似:
POST /1j92n011 HTTP/1.1
User-Agent: python-requests/1.1.0 CPython/3.3.0 Darwin/12.2.0
Host: requestb.in
Content-Type: multipart/form-data; boundary=e8c3c3c5bb9440d1ba0a5fe11956e28d
Content-Length: 2182
Connection: close
Accept-Encoding: identity, gzip, deflate, compress
Accept: */*
--e8c3c3c5bb9440d1ba0a5fe11956e28d
Content-Disposition: form-data; name="AWSAccessKeyId"; filename="AWSAccessKeyId"
Content-Type: application/octet-stream
<opaque_string>
--e8c3c3c5bb9440d1ba0a5fe11956e28d
Content-Disposition: form-data; name="key"; filename="key"
Content-Type: application/octet-stream
<opaque_string>
--e8c3c3c5bb9440d1ba0a5fe11956e28d
Content-Disposition: form-data; name="Policy"; filename="Policy"
Content-Type: application/octet-stream
<opaque_string>
--e8c3c3c5bb9440d1ba0a5fe11956e28d
Content-Disposition: form-data; name="content-type"; filename="content-type"
Content-Type: application/octet-stream
text/plain
--e8c3c3c5bb9440d1ba0a5fe11956e28d
Content-Disposition: form-data; name="success_action_redirect"; filename="success_action_redirect"
Content-Type: application/octet-stream
https://ian.test.instructure.com/api/v1/files/30652688/create_success?uuid=<opaque_string>
--e8c3c3c5bb9440d1ba0a5fe11956e28d
Content-Disposition: form-data; name="Signature"; filename="Signature"
Content-Type: application/octet-stream
<opaque_string>
--e8c3c3c5bb9440d1ba0a5fe11956e28d
Content-Disposition: form-data; name="acl"; filename="acl"
Content-Type: application/octet-stream
private
--e8c3c3c5bb9440d1ba0a5fe11956e28d
Content-Disposition: form-data; name="Filename"; filename="Filename"
Content-Type: application/octet-stream
--e8c3c3c5bb9440d1ba0a5fe11956e28d
Content-Disposition: form-data; name="file"; filename="log.txt"
Content-Type: text/plain
This is my awesome test file.
--e8c3c3c5bb9440d1ba0a5fe11956e28d--
但是,当我尝试将其发布到https://instructure-uploads.s3.amazonaws.com/时,我仍然会返回 500 。我尝试将打开的文件对象添加到files
,然后通过 dict 在单独的 dict 中提交所有其他值data
,但这也不起作用。