Загрузка zip-файла непосредственно в AWS S3 с использованием Python urllib2

Я пытаюсь загрузить zip-файл непосредственно на S3 с помощью скрипта Python, но сталкиваюсь с некоторыми ошибками декодирования Unicode.

Что я делаю, так это генерирую предварительно подписанную ссылку S3, а затем загружаю в нее данные. Я знаю, что ссылка работает нормально, потому что загрузка работает, когда я использую curl, чтобы сделать это следующим образом:

curl -v -H "Content-Type: application/zip" -T /Path/To/Local/File.zip https://MySignedAWSS3Link

Однако, когда я пытаюсь сделать это в Python, используя приведенный ниже код, я получаю сообщение об ошибке.

infile2 = open('/Path/To/Local/File.zip', 'rb')
filedata2 = infile2.read()
request2 = urllib2.Request("https://MySignedAWSS3Link",data=filedata2)
request2.add_header('Content-Type', 'application/zip')
request2.get_method = lambda: 'PUT'
url2 = opener.open(request2)  

Я получаю следующую ошибку/трассировку в Python:

> Traceback (most recent call last):
  File "putFiles.py", line 44, in <module>
    url2 = opener.open(request2)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 404, in open
    response = self._open(req, data)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 422, in _open
    '_open', req)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 382, in _call_chain
    result = func(*args)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1222, in https_open
    return self.do_open(httplib.HTTPSConnection, req)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1181, in do_open
    h.request(req.get_method(), req.get_selector(), req.data, headers)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 973, in request
    self._send_request(method, url, body, headers)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 1007, in _send_request
    self.endheaders(body)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 969, in endheaders
    self._send_output(message_body)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 827, in _send_output
    msg += message_body
UnicodeDecodeError: 'ascii' codec can't decode byte 0xca in position 10: ordinal not in range(128)

Что я здесь делаю неправильно?


person SudoKill    schedule 04.02.2015    source источник
comment
почему бы вам просто не использовать boto?   -  person Dmitry Nedbaylo    schedule 04.02.2015
comment
@DmitryNedbaylo Насколько я понимаю, вы должны предоставить учетные данные AWS для boto. Это сценарий, который будет распространяться, поэтому я не могу указать свои учетные данные AWS. Следовательно, я использую предварительно подписанные URL-адреса, полученные с моего веб-сайта. Я открыт для использования любых других идей, которые позволяют избежать распространения моего секретного ключа AWS.   -  person SudoKill    schedule 05.02.2015
comment
не могли бы вы дать мне трассировку исключения?   -  person Dmitry Nedbaylo    schedule 05.02.2015
comment
@DmitryNedbaylo Привет, Дмитрий, я обновил вопрос с полной трассировкой.   -  person SudoKill    schedule 07.02.2015


Ответы (1)


Согласно вашей трассировке, некоторая строка, добавленная к вашему запросу, является юникодом. Однако, согласно вашему примеру скрипта, все строки закодированы как ascii (поскольку вы используете Python2.7).

С вашей стороны происходят странные вещи, если только вы не установите кодировку Python по умолчанию на UTF-8 (или ОС не установит ее за вас).

Надеюсь, это должно сработать для вас (преобразовать все строки в ascii):

infile2 = open('/Path/To/Local/File.zip', 'rb')
filedata2 = infile2.read()
request2 = urllib2.Request("https://MySignedAWSS3Link".encode('utf-8'),data=filedata2)
request2.add_header(str('Content-Type'), str('application/zip'))
request2.get_method = lambda: str('PUT')
url2 = opener.open(request2)

Обновление: Этот вопрос может и тебе поможет

person Dmitry Nedbaylo    schedule 08.02.2015