我正在用Django和React开发一个Web应用程序,部署在Heroku上,需要文件存储。根据 Heroku 的推荐,我使用的是 Amazon S3。但是,我似乎无法从前端将文件上传到我的 S3 存储桶。根据以下说明:https://devcenter.heroku.com/articles/s3-upload-python,我首先向后端请求签名的请求。 (我可以使用 boto3 在 Python 中很好地设置它,没有任何问题)。然后我使用签名信息尝试将实际文件上传到 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。
我一直在尝试使用
S3Client
中的 @aws-sdk/client-s3
和 PutObjectCommand
来上传对象:
await s3Client.send(new PutObjectCommand(
{
Bucket: string;
Key: string;
Body: File;
Metadata: { string: string };
}
))
我也收到了
400 Bad Request
,结果发现我试图发送的MetaData
太大了。