Python请求是否支持OrderedDicts,还是这里出现其他问题? [英] Does Python-Requests support OrderedDicts, or is something else going wrong here?

查看:94
本文介绍了Python请求是否支持OrderedDicts,还是这里出现其他问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to POST a request to an Amazon S3 endpoint using Python's Requests library. The request is of the multipart/form-data variety, because it includes the POSTing of an actual file.

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

One requirement specified by the API I'm working against is that the file parameter must be posted last. Since Requests uses dictionaries to POST multipart/form-data, and since dictionaries don't follow a dictated order, I've converted it into an OrderedDict called payload. It looks something like this before POSTing it:

{'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'}

这就是我发布它的方式:

And this is how I POST it:

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

响应是500错误,所以我真的不确定这里是什么问题.我只是猜想这与我在Requests中使用OrderedDict有关-我找不到任何文档表明Requests支持或不支持OrderedDicts.这可能是完全不同的东西.

The response is a 500 error, so I'm really not sure what the issue is here. I'm just guessing that it has to do with my use of OrderedDict in Requests—I couldn't find any documentation suggesting Requests does or doesn't support OrderedDicts. It could be something completely different.

还有其他事情会导致请求失败吗?如果需要,我可以提供更多详细信息.

Does anything else stick out to you that would cause the request to fail? I could provide more detail if need be.

好的,请根据Martijn Pieters先前的评论进行更新:

Okay, update, based on Martijn Pieters' earlier comments:

我通过将log.txt文件添加到已创建的upload_data字典中,从而更改了引用log.txt文件的方式,如下所示:

I changed the way I'm referencing the log.txt file by adding it to the already created upload_data dictionary like this:

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

将结果字典打印出来,我得到了:

pprinting the resulting dictionary I get this:

{'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键的值看起来正确吗?

Does that value for the file key look correct?

当我将其发布到RequestBin时,我得到了它,它看起来与Martin的示例非常相似:

When I post it to a RequestBin I get this, which looks pretty similar to Martin's example:

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/.我试过只是将打开的文件对象添加到files,然后通过data在单独的字典中提交所有其他值,但这也不起作用.

However, I still get a 500 returned when I try to POST it to https://instructure-uploads.s3.amazonaws.com/. I've tried just adding the open file object to files and then submitting all the other values in a separate dict through data, but that didn't work either.

推荐答案

您可以传入dict一系列二值元组.

You can pass in either a dict, or a sequence of two-value tuples.

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

And OrderedDict is trivially converted to such a sequence:

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

但是,由于collections.OrderedDict()类型是dict的子类,因此调用items()完全是 requests的作用,因此直接传递OrderedDict实例也可以.

However, because the collections.OrderedDict() type is a subclass of dict, calling items() is exactly what requests does under the hood, so passing in an OrderedDict instance directly Just Works too.

因此,有些其他地方出了问题.您可以通过发布到http://httpbin/post来验证发布的内容:

As such, something else is wrong. You can verify what is being posted by posting to http://httpbin/post instead:

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

很遗憾,httpbin.org不能保留顺序.另外,您也可以在 http://requestb.in/上创建一个专用的HTTP投递箱;它会更详细地告诉您发生了什么.

Unfortunately, httpbin.org does not preserve ordering. Alternatively, you can create a dedicated HTTP post bin at http://requestb.in/ as well; it'll tell you in more detail what goes on.

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

Using requestb.in, and by replacing '@log.txt' with an open file object, the POST from requests is logged as:

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语法;而是传入一个打开的文件对象:

Note that requests does not support the Curl-specific @filename syntax; instead, pass in an open file object:

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

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

You may also want to set the content-type field to use title case: 'Content-Type': ...

如果您仍然收到500响应,请查看r.text响应文本以查看Amazon认为错了的地方.

If you still get a 500 response, check the r.text response text to see what Amazon thinks is wrong.

这篇关于Python请求是否支持OrderedDicts,还是这里出现其他问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆