如何在 Heroku 上为 AWS S3 正确设置签名 url 上传?
How to correctly setup signed url uploads for AWS S3 on Heroku?
问题
我在 Heroku 上有一个简单的应用程序 运行,用户可以在其中上传和查看 images/videos。我正在尝试使用签名 url。我试过了this tutorial and this one。事实上,我克隆了 Github 仓库。问题是每当我尝试上传图片时,我都会收到这些错误:
[错误] 预检响应不成功
[错误] 由于访问控制检查,无法加载 XMLHttpRequest(长 link)。
[错误] 加载资源失败:预检响应不成功(img.jp2,第 0 行)
具体问题
我认为问题可能出在 S3 存储桶设置上,因为我对 AWS 的使用经验不多。所以我的问题是是什么导致了这个问题,我该如何解决?
这是我的 COR 配置
<?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>
<AllowedMethod>HEAD</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
这是生成预签名 url
的代码
aws.config.region = 'us-west-1';
BUCKET = process.env.S3_BUCKET;
app.get('/account', (req, res) => res.render('account.html'));
app.get('/sign-s3', (req, res) => {
const s3 = new aws.S3();
const fileName = req.query['file-name'];
const fileType = req.query['file-type'];
const s3Params = {
Bucket: S3_BUCKET,
Key: fileName,
Expires: 60,
ContentType: fileType,
ACL: 'public-read'
};
s3.getSignedUrl('putObject', s3Params, (err, data) => {
if(err){
console.log(err);
return res.end();
}
const returnData = {
signedRequest: data,
url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}`
};
res.write(JSON.stringify(returnData));
res.end();
});
});
这是尝试上传到 S3 的代码
function uploadFile(file, signedRequest, url){
const xhr = new XMLHttpRequest();
xhr.open('PUT', signedRequest);
xhr.onreadystatechange = () => {
if(xhr.readyState === 4){
if(xhr.status === 200){
alert('success')
}
else{
alert('Could not upload file.');
}
}
};
xhr.send(file);
}
什么都试过了
添加
<AllowedMethod>OPTIONS</AllowedMethod>
结果
Found unsupported HTTP method in CORS config. Unsupported method is OPTIONS
补充说明
我已经尝试过 chrome 和 safari。原来我不小心默认使用
<AllowedHeader>authorization</AllowedHeader>
改回
<AllowedHeader>*</AllowedHeader>
结果:
[Long link] Failed to load resource: the server responded with a status of 403 (Forbidden)
我想我发现了问题,你应该设置 content-type
因为它在生成签名时也会被使用。
xhr.setRequestHeader("Content-Type", "application/octet-stream");
Heroku 教程遗漏了一些细节(或需要更新):
需要更新的配置:
aws.config.region = 'us-west-1';
aws.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
})
问题
我在 Heroku 上有一个简单的应用程序 运行,用户可以在其中上传和查看 images/videos。我正在尝试使用签名 url。我试过了this tutorial and this one。事实上,我克隆了 Github 仓库。问题是每当我尝试上传图片时,我都会收到这些错误:
[错误] 预检响应不成功
[错误] 由于访问控制检查,无法加载 XMLHttpRequest(长 link)。
[错误] 加载资源失败:预检响应不成功(img.jp2,第 0 行)
具体问题
我认为问题可能出在 S3 存储桶设置上,因为我对 AWS 的使用经验不多。所以我的问题是是什么导致了这个问题,我该如何解决?
这是我的 COR 配置
<?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>
<AllowedMethod>HEAD</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
这是生成预签名 url
的代码aws.config.region = 'us-west-1';
BUCKET = process.env.S3_BUCKET;
app.get('/account', (req, res) => res.render('account.html'));
app.get('/sign-s3', (req, res) => {
const s3 = new aws.S3();
const fileName = req.query['file-name'];
const fileType = req.query['file-type'];
const s3Params = {
Bucket: S3_BUCKET,
Key: fileName,
Expires: 60,
ContentType: fileType,
ACL: 'public-read'
};
s3.getSignedUrl('putObject', s3Params, (err, data) => {
if(err){
console.log(err);
return res.end();
}
const returnData = {
signedRequest: data,
url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}`
};
res.write(JSON.stringify(returnData));
res.end();
});
});
这是尝试上传到 S3 的代码
function uploadFile(file, signedRequest, url){
const xhr = new XMLHttpRequest();
xhr.open('PUT', signedRequest);
xhr.onreadystatechange = () => {
if(xhr.readyState === 4){
if(xhr.status === 200){
alert('success')
}
else{
alert('Could not upload file.');
}
}
};
xhr.send(file);
}
什么都试过了
添加
<AllowedMethod>OPTIONS</AllowedMethod>
结果
Found unsupported HTTP method in CORS config. Unsupported method is OPTIONS
补充说明
我已经尝试过 chrome 和 safari。原来我不小心默认使用
<AllowedHeader>authorization</AllowedHeader>
改回
<AllowedHeader>*</AllowedHeader>
结果:
[Long link] Failed to load resource: the server responded with a status of 403 (Forbidden)
我想我发现了问题,你应该设置 content-type
因为它在生成签名时也会被使用。
xhr.setRequestHeader("Content-Type", "application/octet-stream");
Heroku 教程遗漏了一些细节(或需要更新):
需要更新的配置:
aws.config.region = 'us-west-1';
aws.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
})