我目前在泡菜中,我不确定如何进行。
我目前正在建立一个完整的消息传递平台,用户可以在其中相互发送带有附件的消息。它与精简电子邮件系统非常相似。
我希望用户上传的文件托管在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")
上面是我通过Postman将文件发布到的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
这是一个示例的预签名网址:
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方面的错误(我假设我造成错误的可能性是AWS团队的100倍,哈哈。)我有个主意,这可能是因为URL的方式已编码,但我不确定。感谢您的帮助。