首页 > 解决方案 > 400 错误请求上传到带有签名请求的 Amazon S3

问题描述

我正在用 Django 和 React 开发一个 webapp,部署在 Heroku 上,需要文件存储。按照 Heroku 的建议,我使用的是 Amazon S3。但是,我似乎无法从前端将文件上传到我的 S3 存储桶。按照这些说明:https ://devcenter.heroku.com/articles/s3-upload-python ,我首先向后端请求签名请求。(我能够在 Python 中很好地设置它,而使用 boto3 没有任何问题)。然后我使用签名信息尝试将实际文件上传到 S3。但是这样做时,我不断收到 400 Bad Request 错误。

同样奇怪的是,我必须启用公共访问才能获得 400 错误,因为我曾经遇到过403 Forbidden错误,即使使用签名凭据也是如此。

这是我的代码:

const config = { headers: { 'Content-Type': 'application/json' } }
const file_name = file.name
const file_type = file.type
const body = JSON.stringify({ file_name, file_type });
axios.post('/api/triggers/create/video/sign_request', body, config)
.then(res => {
  let content = {}
  for (var key in res.data.data.fields) {
    content[key] = res.data.data.fields[key]
  }
  content['file'] = file
  const config = { headers: { 'Content-Type': file.type } }
  axios.put(res.data.data.url, content, config)
  //...
})

我更喜欢使用 axios,但我也尝试了以下代码,它在上面的 Heroku 教程中使用过。不幸的是,这会产生相同的结果。

const file_name = file.name
const file_type = file.type
const body = JSON.stringify({ file_name, file_type });
axios.post('/api/triggers/create/video/sign_request', body, config)
.then(res => {
  var fd = new FormData()
  for (var key in res.data.data.fields) {
    fd.append(key, res.data.data.fields[key])
  }
  fd.append('file', file)
  var xhr = new XMLHttpRequest();
  xhr.open('POST', res.data.data.url, true);
  xhr.send(fd)
  //...
})

用于签署请求的凭证与对 S3 具有完全访问权限的 IAM 用户相关联。在此处输入图像描述

我从 Django 后端返回的签名请求如下所示:

{
    "data": {
        "url": "https://my-bucket.s3.amazonaws.com/",
        "fields": {
            "acl": "public-read",
            "Content-Type": "video/mp4",
            "key": "funnycatisfunny.mp4",
            "AWSAccessKeyId": "BLABLABLAACCESSKEYBLABLABLA",
            "policy": "eyJleHBpcmF0aW9uIjogIjIwMjAtMDQtMDJUMTU6NDg6MTlaIiwgEtceteraEtCeterA",
            "signature": "S1GnAtuREWdleI4WXv5WHEBjc="
        }
    },
    "url": "https://my-bucket.s3.amazonaws.com/funnycatisfunny.mp4"
}

我曾经遇到过由于 CORS 引起的问题,但是在指定以下配置后这些问题就消失了:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

我认为问题可能是 S3 存储桶缺少策略的结果,所以我指定了一个:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:Put*",
            "Resource": "arn:aws:s3:::my-bucket/*"
        }
    ]
}

这也没有改变事情。

不能把我的头绕在这个上面。任何帮助是极大的赞赏。

更新:事实证明,我将文件放在错误的 url 上,即存储桶 url,而应该始终将文件放在 bucketurl/filename上。调整它允许我将文件上传到 S3。但是,一旦我再次阻止公共访问,我就会像以前一样收到403 Forbidden

标签: javascriptajaxamazon-s3http-status-code-403http-status-code-400

解决方案


推荐阅读