问题描述
我已经尝试了几天使s3上传直接从浏览器工作。
我正在使用jQuery ajax请求在服务器上查询签名的url(以确保用户已通过身份验证)。 然后,我返回签名的URL,并使用另一个jQuery ajax调用来尝试上传文件。
我的后端node.js代码:
exports.getSignedUrl = async (key,content) => {
try {
if (!key){
return Promise.reject('No key supplied');
}
if (!content){
return Promise.reject('No content type supplied');
}
const s3 = new AWS.S3({
region: 'eu-west-1',signatureVersion: 'v4'
});
let params = {
Bucket: siteSettings.s3Bucket,Key: key,ContentType: content,Expires: process.env.S3_UPLOAD_TIME || 240
};
let url = await s3.getSignedUrl('putObject',params);
return Promise.resolve(url);
} catch (error) {
return Promise.reject(error);
}
}
传递的params
变量包含:
{
Bucket:"[bucketname]"
ContentType:"image/jpeg"
Key:"ctl/5f43d07cbeb97850f4fa5246-small.jpg"
}
这会产生如下网址:
https://[bucketname].s3.eu-west-1.amazonaws.com/ctl/5f43d07cbeb97850f4fa5246-small.jpg?Content-Type=image%2Fjpeg&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAXBXXXXXXXXXXBWVG%2F20200923%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20200923T101959Z&X-Amz-Expires=900&X-Amz-Signature=474415e11b9eec7636ab8a1995a28f92cebab18949fb981d37b6c6772209f039&X-Amz-SignedHeaders=host
我的浏览器代码:
const getActiveS3SignedUri = (filename,content,callback) => {
$.ajax({
method: 'POST',url: baseUrl + '/aws/getsignedurl',data: {
filename: filename,content: content
},dataType: 'json',complete: (data) => {
if (data.responseJSON && data.responseJSON.success==true){
callback(null,data.responseJSON);
} else {
if (data.responseJSON.err || data.responseJSON.error){
callback(data.responseJSON.err || data.responseJSON.error);
} else {
callback(`Couldn't get URL,unknown error`);
}
}
}
})
}
const uploadToS3 = (url,fileObject,callback) => {
let file = document.getElementById(fileObject).files[0];
$.ajax({
method: 'POST',// I have tried both POST and PUT here
headers: {"Content-Type": file.type},processData: false,url: url,data: file,complete: (data) => {
callback(null,data);
}
})
}
$(() => {
$('#summernote').summernote({
callbacks: {
onImageUpload: function(files) {
// upload image to S3 server and create imgNode...
$summernote.summernote('insertNode',imgNode);
}
}
});
$('#validate-target').on('submit',(e) => {
//- let input = $('#input_dummy');
//- let val = $('#input_quill > .ql-editor');
//- input.val(val.html());
});
$('#summernote-input').on('change',(e) => {
let fileInput = $(e.target);
let file = fileInput[0].files[0];
getActiveS3SignedUri(file.name,file.type,(err,response) => {
if (!err){
uploadToS3(response.url,'summernote-input',data) => {
alert(JSON.stringify(data));
});
}
})
});
这会将以下内容发布到AWS URL:
Host: [bucketname].s3.eu-west-1.amazonaws.com
Connection: keep-alive
Content-Length: 12147
Accept: */*
DNT: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/85.0.4183.102 Safari/537.36
Content-Type: image/jpeg
Origin: http://localhost:3000
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:3000/admin/settings/
Accept-Encoding: gzip,deflate,br
Accept-Language: en-US,en;q=0.9,en-GB;q=0.8
带有请求有效载荷:
我经常遇到以下错误:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>AKIAXBXXXXXXXXXXBWVG</AWSAccessKeyId><StringToSign>AWS4-HMAC-SHA256
20200923T102902Z
20200923/eu-west-1/s3/aws4_request
9d9d71f4434cbbc236336d33db9e377e2c5790e1acb200e35ece8d25bc96c15b</StringToSign><SignatureProvided>41f375741726f222bcb86018ffae317f9e2a58891105b46783d5f7b343c97352</SignatureProvided><StringToSignBytes>...truncated...</StringToSignBytes><CanonicalRequest>POST
/ctl/5f43d07cbeb97850f4fa5246-small.jpg
Content-Type=image%2Fjpeg&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAXBWXRFJB4RKEBWVG%2F20200923%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20200923T102902Z&X-Amz-Expires=900&X-Amz-SignedHeaders=host
host:toy-lib-dev-bucket.s3.eu-west-1.amazonaws.com
host
UNSIGNED-PAYLOAD</CanonicalRequest><CanonicalRequestBytes>...truncated...</CanonicalRequestBytes><RequestId>470D4BB6D67CDF82</RequestId><HostId>GmktGQDhTmi5a/26bR82tY/SE0C1DQdSZnGNAyp6VGmpYBoTgKXFuTlAYuZpYVCBgdc1Grck6CE=</HostId></Error>
我的s3存储桶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>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
我注意到返回的URL中的X-Amz-Date
比现在晚了一个小时,我假设我现在处于BST时区的UTC,这可能引起问题吗?我尝试将有效期设置为3700秒,但这没有帮助。
到目前为止,我已经尝试了以下方法以使其正常工作:
- 在POST和PUT方法之间更改
- 已删除的过期超时
- 已删除的内容类型
- 指定的内容类型为表单/多部分
- 尝试未在S3对象上指定区域和/或signatureVersion
- 已将仅文件发送的数据更改为对象
{file: file}
到目前为止,我没有任何进展,我错过了什么吗?
编辑:
我尝试使用fetch
代替$.ajax
,但这似乎没有问题:
fetch(url,{
method: "PUT",body: file,});
解决方法
@bendataclear将图像文件转换为blob或base64字符串,然后对其进行处理。