我对使用 AWS S3 很陌生,并且正在尝试将图像上传到 S3,但遇到了臭名昭著的 SignatureDoesNotMatch 错误。我确保有任何拼写错误:(即键中的前导,尾随空格),检查我的系统时间是否关闭,但都无济于事。我的工作流程如下(如果您想参考,主要取自教程:https://medium.com/@diego.f.rodriguezh/direct-image-upload-to-aws-s3-with-react-and-express-2f063bc15430)。我尝试关注之前关于此问题的所有帖子,但仍然无法解决。
首先,在queries.js中,我处理URL的签名:
accessKeyId: process.env.S3_KEY, // stored in the .env file secretAccessKey: process.env.S3_SECRET, // stored in the .env file region: process.env.BUCKET_REGION // This refers to your bucket configuration. }); // Creating a S3 instance const s3 = new AWS.S3(); // Retrieving the bucket name from env variable const Bucket = process.env.BUCKET_NAME; // PUT URL Generator function generatePutUrl(Key, ContentType) { return new Promise((resolve, reject) => { // Note Bucket is retrieved from the env variable above. console.log('the key is:', Key) const params = { Bucket, ContentType, Expires:3600, Key }; // Note operation in this case is putObject s3.getSignedUrl('putObject', params, function(err, url) { if (err) { console.log(err) reject(err); } // If there is no errors we can send back the pre-signed PUT URL resolve(url); }); }); }
然后在index.js中:
// PUT URL
app.get('/generate-put-url', (req,res)=>{
// Both Key and ContentType are defined in the client side.
// Key refers to the remote name of the file.
// ContentType refers to the MIME content type, in this case image/jpeg
const { Key, ContentType } = req.query;
generatePutUrl(Key, ContentType).then(putURL => {
console.log({putURL})
res.send({putURL});
})
.catch(err => {
res.send(err);
});
});
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
然后是我的组件uploader.js,它真正呈现了上传按钮,我在那里对签名的url发出get请求,然后我返回它对S3发出put请求:
getImage = e => {
const files = e.target.files;
if (files && files.length > 0) {
const file = files[0];
this.setState({ file });
}
};
uploadFile = e => {
e.preventDefault();
const { file } = this.state;
this.setState({message:'Uploading...'})
const contentType = file.type; // eg. image/jpeg or image/svg+xml
console.log(contentType)
const generatePutUrl = 'http://localhost:4000/generate-put-url';
const options = {
params: {
Key: file.name,
ContentType: contentType,
},
headers: {
'Content-Type': contentType
}
};
axios.get(generatePutUrl, options).then(res => {
const {
data: { putURL }
} = res;
axios
.put(putURL, file, options)
.then(res => {
this.setState({message:'Upload Successful'})
setTimeout(()=>{
this.setState({message:''});
document.querySelector('#upload-image').value='';
}, 2000)
})
.catch(err => {
this.setState({message:'Sorry, something went wrong'})
console.log('err', err);
});
});
};
作为参考,我在输入放置请求之前记录了我的签名 URL,它看起来像这样(访问密钥 x-ed 输出)
putURL: 'https://polici-media.s3.us-east-2.amazonaws.com/32bitadder.JPG?Content-Type=image%2Fjpeg&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIXXXXXXXXXXX%2F20200627%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20200627T050401Z&X-Amz-Expires=3600&X-Amz-Signature=d12f6228e20d3bc5fab2b38bd6e250992f3e362418eb8f61ed6c886a71eb46e7&X-Amz-SignedHeaders=host'
对于那些可能在教程中跟随的人来说,我真正改变的只是在后端使用端口3500到端口4000,但在这种情况下这不是问题。我也把这个URL放在邮递员中没有用,尽管URLhttps://polici-media.s3.us-east-2.amazonaws.com/32bitadder.JPG具有正确的标头和身份验证,在邮递员身上工作正常
我通过从标题
中删除内容类型来解决此问题。