【问题标题】:Uploading to Amazon S3 using a signed URL使用签名 URL 上传到 Amazon S3
【发布时间】:2021-09-29 06:53:39
【问题描述】:

我正在实现将由 Angular 应用程序使用的文件上传功能。但是我在让它工作时遇到了很多问题。并且需要帮助弄清楚我错过了什么。以下是现有资源的概述,以及我得到的测试和结果。

基础设施

  • 我创建的 Amazon S3 存储桶启用了版本控制、启用了加密并且所有公共访问都被阻止。
  • 具有 Lambda 函数的 API 网关可生成预签名 URL。代码如下所示。
    def generate_upload_url(self):
        try:
            conditions = [
                {"acl": "private"},
                ["starts-with", "$Content-Type", ""]
            ]
            fields = {"acl": "private"}
            response = self.s3.generate_presigned_post(self.bucket_name,
                                                       self.file_path,
                                                       Fields=fields,
                                                       Conditions=conditions,
                                                       ExpiresIn=3600)
        except ClientError as e:
            logging.error(e)
            return None
        return response

  • 存储桶名称和文件路径设置为类构造函数的一部分。在此示例中,存储桶和文件路径为
    def construct_file_names(self):
        self.file_path = self.account_number + '-' + self.user_id + '-' + self.experiment_id + '-experiment-data.json'
        self.bucket_name = self.account_number + '-' + self.user_id + '-resources'

通过 Postman 测试

在我的 Angular 应用程序中实现它之前。我正在通过 Postman 测试上传功能。

  • 我的 API 端点对预签名 URL 的响应如下所示

  • 使用这些值,我从 Postman 发出另一个 API 调用并收到以下响应

如果有人能看到我在这里可能做错了什么。我在 boto3 方法中使用了不同的字段,但最终,我收到了 403 错误,其中包含与策略条件相关的不同消息。任何帮助将不胜感激。

更新 1

  • 我尝试调整“file”和“acl”的顺序,但收到另一个错误,如下所示

更新二 - 使用签名 v4

  • 我更新了预签名的 URL 代码,如下所示
def upload_data(x):
    try:
        config = Config(
            signature_version='s3v4',
        )
        s3 = boto3.client('s3', "eu-west-1", config=config)
        sts = boto3.client('sts', "eu-west-1")
        data_upload = UploadData(x["userId"], x["experimentId"], s3, sts)
        return data_upload.generate_upload_url()
    except Exception as e:
        logging.error(e)


  • 当 API 调用触发 Lambda 函数时,Postman 会收到以下内容

  • 使用从 API 返回的新键值,我继续尝试另一个测试上传。结果如下所示

又是一个错误,但我认为我正在朝着正确的方向前进。

【问题讨论】:

    标签: amazon-web-services amazon-s3 file-upload postman


    【解决方案1】:

    尝试将acl 移动到file 行上方。确保file 在末尾。

    【讨论】:

    • 当我调整订单时,我收到另一条错误消息。我会在上面添加它。
    • @hynespm 使用s3v4var s3 = new AWS.S3({signatureVersion: 'v4'});
    【解决方案2】:

    我终于得到了这个工作,所以我会在这里发布一个答案,总结所采取的步骤。

    在 eu-west-1 中通过 boto 生成预签名 URL 的 Python 代码

    def upload_data(x):
        try:
            config = Config(
                signature_version='s3v4',
            )
            s3 = boto3.client('s3', "eu-west-1", config=config)
            sts = boto3.client('sts', "eu-west-1")
            data_upload = UploadData(x["userId"], x["experimentId"], s3, sts)
            return data_upload.generate_upload_url()
        except Exception as e:
            logging.error(e)
    
        def generate_upload_url(self):
            try:
                conditions = [
                    {"acl": "private"},
                    ["starts-with", "$Content-Type", ""]
                ]
                fields = {"acl": "private"}
                response = self.s3.generate_presigned_post(self.bucket_name,
                                                           self.file_path,
                                                           Fields=fields,
                                                           Conditions=conditions,
                                                           ExpiresIn=3600)
            except ClientError as e:
                logging.error(e)
                return None
            return response
    
    
    

    通过 Postman 上传

    • 确保顺序正确,“文件”排在最后
    • 确保“Content-Type”与生成 URL 的代码中的内容相匹配。就我而言,它是“”。添加后,收到的条件错误就消失了。

    S3 存储桶

    [
        {
            "AllowedHeaders": [
                "*"
            ],
            "AllowedMethods": [
                "PUT",
                "POST",
                "DELETE"
            ],
            "AllowedOrigins": [
                "*"
            ],
            "ExposeHeaders": [],
            "MaxAgeSeconds": 3000
        }
    ]
    

    通过 Angular 上传

    我的问题是在使用 Postman 进行测试时出现的,但我正在实现要由 Angular 应用程序使用的功能。这是一个代码sn-p,它是如何通过首先调用预签名URL的API,然后直接上传来完成上传的。

    总结

    • 检查您的 S3 基础架构
    • 根据需要启用 CORS
    • 如果在旧地区工作,请在所选 SDK 中明确使用 sig 4
    • 确保表单数据顺序正确

    希望所有这些作品都能帮助其他正在努力实现相同目标的人。感谢 SO 成员的所有提示。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-15
      • 2021-12-10
      • 2014-11-17
      • 2013-10-19
      • 2023-04-09
      • 2018-12-27
      • 2021-08-26
      • 2019-04-18
      相关资源
      最近更新 更多