1

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

4

0 回答 0