S3インスタンスにファイルを投稿するクライアントアプリケーションを作成していますが、以下のコードを使用すると、応答がなく、ファイルが投稿されません。サーバーにクレデンシャルを入力することで機能し、クライアントはその詳細を使用してs3インスタンスに接続し(またはこれが機能している場合は)、ファイルをアップロードします。
import httplib, urllib, json
setup_headers = {"Content-Type": "application/json", "Accept": "text/plain"}
conn = httplib.HTTPSConnection("www.server.address")
conn.request("GET", "/api/data/upload-request/", '', setup_headers)
response = conn.getresponse()
response_data = response.read()
print response_data
aws_setup = json.loads(response_data)
aws_setup.update({'filename':'fname.zip', 'file': open('fname.zip', 'rb').read()})
aws_params = urllib.urlencode(aws_setup)
aws_headers = {'Content-Type':'multipart/form-data'}
aws_conn = httplib.HTTPSConnection("address.s3.amazonaws.com")
aws_conn.request("POST", "", aws_params, aws_headers)
aws_conn.close()
conn.close()
最初の接続要求オブジェクトから返されるもの:
{"AWSAccessKeyId": "correct key", "success_action_redirect": "http://our.web.address/api/upload-success/", "acl": "private", "key": "${filename}", "signature": "signature", "policy": "encoded policy", "Content-Type": "application/zip"}
マルチパートフォームデータに問題があるため、これは失敗していました。私が遭遇している新しい問題は、encode_multipart_formdataでエラーが発生していることです。ファイルタイプオブジェクトを渡すと、文字列結合が試行され、失敗します。文字列を渡すと、明らかにファイルの内容が取り込まれず、ファイルの内容全体をメモリに読み込んで渡したくありません。コードと両方のエラーレポートは以下のとおりです。
import httplib
import json
import mimetypes
def post_multipart(host, selector, fields, files):
"""
Post fields and files to an http host as multipart/form-data.
fields is a sequence of (name, value) elements for regular form fields.
files is a sequence of (name, filename, value) elements for data to be uploaded as files
Return the server's response page.
"""
content_type, body = encode_multipart_formdata(fields, files)
h = httplib.HTTPSConnection(host)
header = {
'User-Agent': 'Mozilla/5.0',
'Content-Type': content_type
}
h.request('POST', selector, body, header)
res = h.getresponse()
return res.status, res.reason, res.read()
def encode_multipart_formdata(fields, files):
"""
fields is a sequence of (name, value) elements for regular form fields.
files is a sequence of (name, filename, value) elements for data to be uploaded as files
Return (content_type, body) ready for httplib.HTTP instance
"""
BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
CRLF = '\r\n'
L = []
for key, value in fields.iteritems():
L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"' % key)
L.append('')
L.append(value)
for (key, filename, value) in files:
L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
L.append('Content-Type: %s' % get_content_type(filename))
L.append('')
L.append(value)
L.append('--' + BOUNDARY + '--')
L.append('')
body = CRLF.join(L)
content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
return content_type, body
def get_content_type(filename):
return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
setup_headers = {"Content-Type": "application/json", "Accept": "text/plain"}
conn = httplib.HTTPSConnection("our.server.address")
conn.request("GET", "/api/data/upload-request/", '', setup_headers)
response = conn.getresponse()
response_data = response.read()
aws_setup = json.loads(response_data)
status, reason, data = post_multipart("address.s3.amazonaws.com", "", aws_setup, [['upload_file.zip', 'upload_file.zip', open("upload_file.zip")]])
print status
print reason
print data
conn.close()
上記のコードに示されているファイルタイプオブジェクトのエラー:
TypeError: sequence item 32: expected string or Unicode, file found
代わりに文字列が渡されるとエラーが発生します:
400
Bad Request
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>InvalidArgument</Code><Message>POST requires exactly one file upload per request.</Message><ArgumentValue>0</ArgumentValue><ArgumentName>file</ArgumentName><RequestId>9AA6411E13792EC6</RequestId><HostId>EkkcNUkIWIVk8wbhEplhp0L+Rqsa089TD0VusgMUQsQJo3rUUf/zbP+k67fEzolc</HostId></Error>
boto(私が仕事に取り掛かった)でこれを行うには、クライアント側に秘密鍵を表示する必要がありました。