【问题标题】:Adding Content-Encoding header to signed URL uploaded files将 Content-Encoding 标头添加到签名的 URL 上传文件
【发布时间】:2019-01-10 02:13:07
【问题描述】:

我需要通过签名 URL 将 Gziped 内容上传到 S3。

以下是我使用 JS 后端生成签名 URL 的方法:

s3.createPresignedPost({
  Bucket: 'name',
  Fields: {
    key: 'key'
  }
})

我尝试将Content-Encoding 标头传递给signedURL POST 请求,但没有成功。 s3 对象上的标头设置不正确。

我还尝试设置上传后 lambda 来更新元数据。它失败并出现错误File is identical 错误

最后我尝试使用 cloudfront + lambda 来强制标头。这也失败了,错误提示 Content-Enconding 是受保护的错误。

【问题讨论】:

    标签: amazon-s3 pre-signed-url


    【解决方案1】:

    --更新开始--

    对于通过 Ajax 或 JS 脚本上传到 S3,我建议使用 s3.getSignedUrl 方法。 s3.createPresignedPost 仅用于直接浏览器上传。

    以下是我使用this 指南创建的 Ajax jQuery Upload 示例。

    s3.getSignedUrl('putObject', {
        Bucket: 'bucketName',
        Key: 'sample.jpg.gz',
        // This must match with your ajax contentType parameter
        ContentType: 'binary/octet-stream'
        /* then add all the rest of your parameters to AWS puttObect here */
      }, function (err, url) {
        console.log('The URL is', url);
      });
    

    Ajax PUT 脚本 - 从上面的函数调用中获取 Url 并在下面使用它。

    $.ajax({
        type: 'PUT',
        url: "https://s3.amazonaws.com/bucketName/sample.jpg.gz?AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Content-Type=binary%2Foctet-stream&Expires=1547056786&Signature=KyTXdr8so2C8WUmN0Owk%2FVLw6R0%3D",
        //Even thought Content-Encoding header was not specified in signature, it uploads fine.
        headers: {
            'Content-Encoding': 'gzip'
        },
        // Content type must much with the parameter you signed your URL with
        contentType: 'binary/octet-stream',
        // this flag is important, if not set, it will try to send data as a form
        processData: false,
        // the actual file is sent raw
        data: theFormFile
    }).success(function () {
        alert('File uploaded');
    }).error(function () {
        alert('File NOT uploaded');
        console.log(arguments);
    });
    

    在 S3 对象中,您应该在元数据下看到 Content-Type、Content-Encoding。

    重要提示 当您尝试通过在浏览器上运行的 JS 脚本上传时,通常浏览器会在调用 PUT 方法之前先发送 OPTIONS 方法预检(或 CORS 检查)。您将收到 OPTIONS 的 403 Forbidden 错误,因为 S3 存储桶上的 CORS 不允许这样做。我解决的一种方法是在存储桶级别使用以下CORS 配置。 Reference

    <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>PUT</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
    </CORSConfiguration>
    

    --更新结束--

    你试过这样吗?我刚刚使用 AWS 文档中给出的示例 html 测试了该策略。参考——https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html

    s3.createPresignedPost({
      Bucket: 'name',
      Conditions: [
        { "Content-Encoding": "gzip" }
      ],
      Fields: {
        key: 'key'
      }
    })
    

    更新 - 这是我目前的观察结果。

    我们确实需要检查您的客户端正在执行上传操作。如果您想在 MetaData 上设置 Content-Encoding,那么您的预签名 URL 应该设置 Content-Encoding 属性。如果 Signed Url 没有,但您的请求标头有,那么它将给您Extra input fields: content-encoding

    我已经使用 Content-Encoding 签署了一个 url,并上传了一个带有以下示例 html 的压缩文件。

    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      </head>
      <body>
      <form action="http://bucket-name.s3.amazonaws.com" method="post" enctype="multipart/form-data">
        Key to upload: 
        <input type="input"  name="key" value="sample.jpg.gz" /><br />
        Content-Encoding: 
        <input type="input"  name="Content-Encoding" value="gzip" /><br />
        <input type="text"   name="X-Amz-Credential" value="AKIAIOSFODNN7EXAMPLE/20190108/us-east-1/s3/aws4_request" />
        <input type="text"   name="X-Amz-Algorithm" value="AWS4-HMAC-SHA256" />
        <input type="text"   name="X-Amz-Date" value="20190108T220828Z" />
        Tags for File: 
        <input type="hidden" name="Policy" value='bigbase64String' />
        <input type="hidden" name="X-Amz-Signature" value="xxxxxxxx" />
        File: 
        <input type="file"   name="file" /> <br />
        <!-- The elements after this will be ignored -->
        <input type="submit" name="submit" value="Upload to Amazon S3" />
      </form>
    </html>
    

    如果我不发送 Content-Encoding 标头,则会给出错误 Policy Condition failed: ["eq", "$Content-Encoding", "gzip"]

    注意 - 如果您在上传时使用https,请确保您在 S3 端点上拥有正确的证书,否则您将收到证书错误。

    S3 屏幕截图。

    【讨论】:

    • 您好,感谢您的建议。我确实尝试过,然后它会产生 403 错误,即使我也在 POST 请求上设置了标头
    • @silkAdmin 你能给出你收到的 403 错误响应吗?不看原因,实际上传时找不到哪个header或者哪个header与签名冲突。
    • @silkAdmin 我明白了。做一件事,获取您从上述方法获得的签名,并使用我在答案中提到的示例html,并尝试使用您的存储桶和签名上传它。您应该会看到来自 S3 的 XML 错误响应,说明与签名冲突的内容。或者,如果您可以捕获带有来自 S3 的详细信息的错误响应消息(这应该说明签名与您的上传冲突)。或者你能提供一个链接到你的代码与 github 以在我结束时复制。
    • 确切的错误是:Invalid according to Policy: Policy Condition failed: ["eq", "$Content-Encoding", "gzip"]。该请求确实具有正确的标头 tho
    • @silkAdmin 我已经根据迄今为止的观察更新了我的答案。能否请您回顾一下并告知您身边发生的事情。
    猜你喜欢
    • 2021-10-20
    • 2012-07-08
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 1970-01-01
    • 2020-02-11
    • 2011-11-09
    相关资源
    最近更新 更多