我正在尝试使用Python的Requests库将请求发布到Amazon S3终端节点。该请求具有multipart / form-data的种类,因为它包括实际文件的POST。

我要针对的API指定的一项要求是,必须最后发布file参数。由于Requests使用字典来发布多部分/表单数据,并且由于字典不遵循命令顺序,因此我将其转换为名为payload的OrderedDict。发布前看起来像这样:

{'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字典中来更改了引用log.txt文件的方式,如下所示:

upload_data['file'] = open("log.txt")


pprinting结果字典我得到这个:

{'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,然后通过data在单独的字典中提交所有其他值,但这也不起作用。

最佳答案

您可以传入dict或两个值的元组序列。

OrderedDict被简单地转换为这样的序列:

r = requests.post("https://instructure-uploads.s3.amazonaws.com/", files=payload.items())


但是,由于collections.OrderedDict()类型是dict的子类,因此调用items()正是requests在后台执行的操作,因此直接传递OrderedDict实例也可以。

因此,还有其他问题。您可以通过发布到http://httpbin/post来验证发布的内容:

import pprint
pprint.pprint(requests.post("http://httpbin.org/post", files=payload.items()).json())


不幸的是,httpbin.org不会保留排序。另外,您也可以在http://requestb.in/上创建一个专用的HTTP post bin。它会更详细地告诉您发生了什么。

使用requestb.in,并用打开的文件对象替换'@log.txt',来自请求的POST记录为:

POST /tlrsd2tl HTTP/1.1
User-Agent: python-requests/1.1.0 CPython/2.7.3 Darwin/11.4.2
Host: requestb.in
Content-Type: multipart/form-data; boundary=7b12bf345d0744b6b7e66c7890214311
Content-Length: 1601
Connection: close
Accept-Encoding: gzip, deflate, compress
Accept: */*

--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="content-type"; filename="content-type"
Content-Type: application/octet-stream

text/plain
--7b12bf345d0744b6b7e66c7890214311
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/30652543/create_success?uuid=<opaque_string>
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="Signature"; filename="Signature"
Content-Type: application/octet-stream

<opaque_string>
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="Filename"; filename="Filename"
Content-Type: application/octet-stream


--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="acl"; filename="acl"
Content-Type: application/octet-stream

private
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="Policy"; filename="Policy"
Content-Type: application/octet-stream

<opaque_string>
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="key"; filename="key"
Content-Type: application/octet-stream

account_95298/attachments/30652543/log.txt
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="AWSAccessKeyId"; filename="AWSAccessKeyId"
Content-Type: application/octet-stream

<opaque_string>
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="file"; filename="log.txt"
Content-Type: text/plain

some
data

--7b12bf345d0744b6b7e66c7890214311--


说明正确保留了订单。

请注意,requests不支持特定于Curl的@filename语法。而是传入一个打开的文件对象:

 'file': open('log.txt', 'rb')


您可能还需要设置content-type字段以使用标题大小写:'Content-Type': ..

如果您仍然收到500响应,请检查r.text响应文本以查看Amazon认为错误的内容。

关于python - Python请求是否支持OrderedDicts,还是这里出现其他问题?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15504638/

10-12 18:51