我正在编写一个客户端应用程序来将文件发布到我们的 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(我开始工作)执行此操作需要让我们的私钥对客户端可见。