2

Pythonのリクエストライブラリを使用してAmazonS3エンドポイントにリクエストをPOSTしようとしています。リクエストには、実際のファイルのPOSTが含まれているため、multipart/form-dataの種類があります。

私が取り組んでいるAPIで指定されている要件の1つは、パラメーターを最後fileに投稿する必要があるということです。Requestsはディクショナリを使用してmultipart/form-dataをPOSTし、ディクショナリは指示された順序に従わないため、それをと呼ばれるOrderedDictに変換しました。投稿する前は次のようになります。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/にPOSTしようとすると、500が返されます。開いているファイルオブジェクトをに追加してからfiles、他のすべての値を別のdictで送信しようとしましdataたが、それも機能しませんでした。

4

2 に答える 2

3

data送信するものを、に渡されるOrderedDictとに送信されるOrderedDictに分割する必要がありますfiles。現在、AWSはデータパラメータをフォームパラメータとしてではなく、ファイルとして(正しく)解釈しています。次のようになります。

data = OrderedDict([
    ('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', ''),
])

files = OrderedDict([('file', open('log.txt'))])

requests.post(url, data=data, files=files)
于 2013-04-02T15:46:52.563 に答える
0

dictまたは2つの値のタプルのシーケンスのいずれかを渡すことができます。

そして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ポストビンを作成することもできます。何が起こっているのかをより詳細に教えてくれます。

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--

順序が正しく保持されていることを示しています。

これはCurl固有の構文requestsをサポートしていないことに注意してください。@filename代わりに、開いているファイルオブジェクトを渡します。

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

content-typeタイトルケースを使用するようにフィールドを設定することもできます'Content-Type': ..

それでも500の応答が返される場合は、応答テキストをチェックして、r.textAmazonが間違っていると考えていることを確認してください。

于 2013-03-19T16:12:23.833 に答える