在执行POST请求时,不会设置Amazon S3内容类型

时间:2014-07-28 00:48:25

标签: php http amazon-web-services amazon-s3

AccessDenied Invalid according to Policy: Extra input fields: content-type

当我有这个

------WebKitFormBoundaryZIsnhgiAKpAVIsBT
Content-Disposition: form-data; name="acl"

public-read
------WebKitFormBoundaryZIsnhgiAKpAVIsBT
Content-Disposition: form-data; name="awsaccesskeyid"

my-access-key-id
------WebKitFormBoundaryZIsnhgiAKpAVIsBT
Content-Disposition: form-data; name="bucket"

my-bucket
------WebKitFormBoundaryZIsnhgiAKpAVIsBT
Content-Disposition: form-data; name="Content-Type"

image/png
------WebKitFormBoundaryZIsnhgiAKpAVIsBT
Content-Disposition: form-data; name="key"

images/anime_girl.png
------WebKitFormBoundaryZIsnhgiAKpAVIsBT
Content-Disposition: form-data; name="policy"

my-policy
------WebKitFormBoundaryZIsnhgiAKpAVIsBT
Content-Disposition: form-data; name="signature"

my-signature
------WebKitFormBoundaryZIsnhgiAKpAVIsBT
Content-Disposition: form-data; name="success_action_status"

201
------WebKitFormBoundaryZIsnhgiAKpAVIsBT
Content-Disposition: form-data; name="file"; filename="anime_girl.png"
Content-Type: image/png

但是,如果我在下面的代码中完全省略了Content Type,则文件会上传但不具备正确的内容类型。

        "acl" => "public-read",
        "awsaccesskeyid" => $s3->getAwsAccessKeyId(),
        "bucket" => $s3->getBucket(),
        "Content-Type" => $inputs['type'],
        "key" => "images/" . $inputs['name'],
        "policy" => $s3->getPolicy(true),
        "signature" => $s3->getSignedPolicy(),
        "success_action_status" => "201"

我还尝试将内容类型添加到policy中,我收到此错误

AccessDenied Invalid according to Policy: Policy Condition failed: ["starts-with", "Content-Type", "image/png"]

我尝试了其他一些建议并收到此错误

AccessDenied Invalid according to Policy: Policy Condition failed: ["eq", "Content-Type", "image/png"]

这是我的角色配置

<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>

那么如何以其他方式指定内容类型或修复此问题?

修改

当我省略任何类型的内容类型时(我没有在后端指定任何内容)我得到了像Ben这样的请求有效负载

------WebKitFormBoundaryUjxIo0gCBYg7AqJt
Content-Disposition: form-data; name="acl"

public-read
------WebKitFormBoundaryUjxIo0gCBYg7AqJt
Content-Disposition: form-data; name="awsaccesskeyid"

xxxx
------WebKitFormBoundaryUjxIo0gCBYg7AqJt
Content-Disposition: form-data; name="bucket"

xxxxx
------WebKitFormBoundaryUjxIo0gCBYg7AqJt
Content-Disposition: form-data; name="key"

images/Elf-Anime-Warrior-Wallpaper.jpg
------WebKitFormBoundaryUjxIo0gCBYg7AqJt
Content-Disposition: form-data; name="policy"

xxxx
------WebKitFormBoundaryUjxIo0gCBYg7AqJt
Content-Disposition: form-data; name="signature"

0BbpI0AP0wL3S1cBfo9n9tOp+N8=
------WebKitFormBoundaryUjxIo0gCBYg7AqJt
Content-Disposition: form-data; name="success_action_status"

201
------WebKitFormBoundaryUjxIo0gCBYg7AqJt
Content-Disposition: form-data; name="file"; filename="Elf-Anime-Warrior-Wallpaper.jpg"
Content-Type: image/jpeg


------WebKitFormBoundaryUjxIo0gCBYg7AqJt--

问题是,在存储桶中,文件的内容类型为binary/octet-stream,因此图像不会在浏览器中查看,而是会被下载(这不是我的内容)想)。因此,当我的请求有效负载如上所述时,我不确定为什么亚马逊没有正确设置内容类型。

3 个答案:

答案 0 :(得分:5)

根据Amazon S3 documentation,您确实可以将Content-Type作为表单字段传递,但是you need to allow that in your policy

所以你需要这样的东西:

<强>策略:

{
  "expiration": "2007-12-01T12:00:00.000Z",
  "conditions": [
    {"acl": "public-read" },
    {"bucket": "johnsmith" },
    ["starts-with", "$key", "user/eric/"],
    ["starts-with", "$Content-Type", ""],
    ...
  ]
}

此处的相关行是["starts-with", "$Content-Type", ""]。文档说明类型&#34;的条件匹配任何&#34;应该是&#34;开始 - &#34;空值。如果要将内容类型限制为某种内容,则应使用["starts-with", "$Content-Type", "image/"],例如。

<强>形式:

(从S3文档中获取的示例,相应地更改值)。

<form action="http://examplebucket.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
  <input type="hidden" name="key" value="user/user1/${filename}">
  <input type="hidden" name="acl" value="public-read">
  <input type="hidden" name="success_action_redirect" value="http://examplebucket.s3.amazonaws.com/successful_upload.html">
  <input type="hidden" name="Content-Type" value="binary/octet-stream">
  <input type="hidden" name="Policy" value='<Base64-encoded policy string>'>
  <input type="hidden" name="x-amz-meta-uuid" value="14365123651274">
  <input type="hidden" name="X-Amz-Signature" value="<signature-value>">
  <input type="hidden" name="X-Amz-Credential" value="AKIAIOSFODNN7EXAMPLE/20130806/us-east-1/s3/aws4_request">
  <input type="hidden" name="X-Amz-Algorithm" value="AWS4-HMAC-SHA256">
  <input type="hidden" name="X-Amz-Date" value="20130806T000000Z">

  Tags for File: 
  <input type="input" name="x-amz-meta-tag" value=""><br>
  File: 
  <input type="file" name="file"><br>

  <input type="submit" name="submit" value="Upload to Amazon S3">
</form>

正如您在第一个有效负载中所做的那样,您确实设置了一个&#34; Content-Type&#34;表格的字段。这与更新的政策一起应该有效。

但请注意,如果您事先知道要上传的文件的类型,则应将策略和表单字段都设置为该类型。但是如果要上传不同类型的文件,则将Content-Type条件设置为&#34;匹配任何&#34;在策略中,您可以编写一个简单的javascript来拦截表单的submit事件,以动态更改Content-Type字段(此处使用jQuery编写):

$("#s3-form").on("submit", function() {
  var contentTypeField = $("input[name='Content-Type']", this),
      fileField = $("input[type='file']", this),
      selectedFiles = fileField.get(0).files;

  if (files.length > 0) {
    // we're uploading a single file, so get the type for the first selected file
    contentTypeField.val(selectedFiles[0].type);
  }
});

答案 1 :(得分:0)

这是我将文件上传到S3时的示例工作请求有效负载:

------WebKitFormBoundary9Vtjs2zgAF5jJgHC
Content-Disposition: form-data; name="key"

uploads/tmp/dbdfc12f-665e-4389-a739-f345e7acea48/svg_3927.zip
------WebKitFormBoundary9Vtjs2zgAF5jJgHC
Content-Disposition: form-data; name="AWSAccessKeyId"

xxx
------WebKitFormBoundary9Vtjs2zgAF5jJgHC
Content-Disposition: form-data; name="acl"

public-read
------WebKitFormBoundary9Vtjs2zgAF5jJgHC
Content-Disposition: form-data; name="policy"

xxx
------WebKitFormBoundary9Vtjs2zgAF5jJgHC
Content-Disposition: form-data; name="signature"

xxx=
------WebKitFormBoundary9Vtjs2zgAF5jJgHC
Content-Disposition: form-data; name="success_action_status"

201
------WebKitFormBoundary9Vtjs2zgAF5jJgHC
Content-Disposition: form-data; name="file"; filename="svg_3927.zip"
Content-Type: application/zip

正如您所看到的,内容类型最后只与文件数据一起设置了一次。

<强>更新

以下是我的开发桶的CORS:

    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>Authorization</AllowedHeader>
    <AllowedHeader>Content-*</AllowedHeader>
    <AllowedHeader>Host</AllowedHeader>
    <AllowedHeader>*</AllowedHeader>

注意<AllowedHeader>Content-*</AllowedHeader>,这可能会解决您的问题。

答案 2 :(得分:-1)

尝试在“婴儿车”中抵消ContentType。级别数组..

"acl" => "public-read",
"awsaccesskeyid" => $s3->getAwsAccessKeyId(),
"bucket" => $s3->getBucket(),
"key" => "images/" . $inputs['name'],
"policy" => $s3->getPolicy(true),
"signature" => $s3->getSignedPolicy(),
"success_action_status" => "201",
// indent "ContentType" within a "params" array
"params" => array(
    "ContentType" => $inputs['type']
)