В настоящее время я нахожусь в довольно напряженном состоянии и не знаю, как поступить.
В настоящее время я создаю платформу обмена сообщениями с полным стеком, где пользователи могут отправлять друг другу сообщения с вложениями. Это очень похоже на урезанную почтовую систему.
Я хочу, чтобы загруженные пользователем файлы размещались на S3. Эта корзина S3 будет (в конце концов) иметь список контроля доступа, но в настоящее время она общедоступна. В результате я пытаюсь осуществить загрузку вложений по заранее заданному URL-адресу, который я отображаю на стороне клиента. Пользователь щелкает URL-адрес, попадает в AWS, и загрузка файла начинается автоматически. По крайней мере, это должно быть поведение.
Когда я загружаю файлы (я делаю это в пакетах по 4 файла, все разные типы файлов), я печатаю предварительно сгенерированные URL-адреса, которые я генерирую, со сроком действия по умолчанию 1 час.
Дело в том, что обычно эти URL работают! Я нажимаю на них, и файл загружается. Однако время от времени я получаю ошибку SignatureDoesNotMatch, редко для всех 4 файлов в пакете, но, возможно, один или два. Похоже, что все остальные сообщения в SO, связанные с этой ошибкой, вызваны неправильной вставкой учетных данных AWS Access, поэтому я обязательно проверил их. Я не уверен, в чем проблема, и хотел бы увидеть, если бы кто-то еще имел эту проблему.
Вот код для моих методов:
class AttachmentTest(APIView):
'''
POST:
Creates an Attachment Model per attachment sent
'''
def post(self, request):
print(request.FILES)
s3 = boto3.resource('s3')
folder_name = str(uuid.uuid4())
for file in request.FILES:
object_key = 'mail_attachments/' + request.user.username + '/' + folder_name + '/' + request.FILES[file].name
s3.Bucket('MY_BUCKET_NAME').put_object(Key=object_key, Body=request.FILES[file], ContentType=request.FILES[file].content_type)
print(create_presigned_url('MY_BUCKET_NAME', object_key))
return Response("attachment logged")
Выше находится конечная точка API, в которую я отправляю файлы через Почтальона.
Вот метод create_presigned_url()
, скопированный прямо из документации AWS:
def create_presigned_url(bucket_name, object_name, expiration=3600):
"""Generate a presigned URL to share an S3 object
:param bucket_name: string
:param object_name: string
:param expiration: Time in seconds for the presigned URL to remain valid
:return: Presigned URL as string. If error, returns None.
"""
# Generate a presigned URL for the S3 object
s3_client = boto3.client('s3')
try:
response = s3_client.generate_presigned_url('get_object',
Params={'Bucket': bucket_name,
'Key': object_name},
ExpiresIn=expiration)
except ClientError as e:
logging.error(e)
return None
# The response contains the presigned URL
return response
Вот примерный URL:
https://<MY_BUCKET_NAME>.s3.amazonaws.com/mail_attachments/isaac/775054eb-a83e-49e1-974d-bbf3f88e32ba/%F0%9F%98%80?AWSAccessKeyId=<MY_ACCESS_KEY>&Signature=SFodxvdJbVvClINL7M%2BZPym273Y%3D&Expires=1561585952
Пожалуйста, дайте мне знать, если вы столкнулись с этой проблемой. Я не уверен, является ли это ошибкой на стороне Amazon (я предполагаю, что вероятность возникновения ошибки в 100 раз выше, чем у команды AWS, хаха.) У меня есть идея, что это может быть связано с тем, как URL закодирован, но я не совсем уверен. Спасибо за помощь.