boto3方法generate_presigned_url()中的行为不一致,有时SignatureDoesNotMatch

时间:2019-06-26 21:23:02

标签: python-3.x amazon-web-services amazon-s3 django-rest-framework boto3

我目前在泡菜中,我不确定如何进行。

我目前正在建立一个完整的消息传递平台,用户可以在其中相互发送带有附件的消息。它与精简电子邮件系统非常相似。

我希望用户上传的文件托管在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的方式已编码,但我不确定。感谢您的帮助。

0 个答案:

没有答案