如何将对象正确上传到 AWS S3?
How to properly upload an object to AWS S3?
经过三天的追逐这个问题。是时候寻求帮助了。
我有一个签名 url 可以将文件上传到 Amazon S3。我知道这是正确的,因为 a
curl -v -T file.png --header "Content-Type:binary/octet-stream" "https://sample.s3.amazonaws.com/33d7e8f0-0fc5-11e5-9d95-2b3410860edd?AWSAccessKeyId=XXXXXXXX&Content-Type=binary%2Foctet-stream&Expires=1433984735&Signature=LUjj8iIAbCfNoskGhqLDhuEWVG4%3D"
正确成功。
但是我的 .ajax 上传代码(如下)使 S3 存储桶中的内容出现轻微乱码。
例如,如果我上传一个 .pdf 文件,它会从 S3 管理控制台正确加载,但如果它是 .png 或 .jpeg 等,它会失败......仔细查看文件长度错误(轻微)。
浏览器调用的核心是:
var formData = new FormData();
formData.append("upload", file);
$.ajax({ url: data.puturl,
type: 'PUT',
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', progressHandlingFunction,
false);
}
return myXhr;
},
success: completeHandler,
error: errorHandler,
data: formData,
cache: $.param(false),
contentType: "binary/octet-stream",
processData: $.param(false)
}, 'json');
这似乎行得通,但数据是乱码。我尝试将内容设置为 file.type 等,但无济于事。我需要在这里做一些编码吗?比如我缺少的base64????
如有任何见解,我们将不胜感激。
或者,如果有一种简单的方法可以不使用 .ajax 来做同样的事情,那就太好了。
根据 'tedder42' 上面提出的问题,以及更多的实验,我意识到发送 FormData 是问题所在。所以我将代码更改为仅使用 FileReader() 并传递原始数据。这非常有效。这是代码:
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function (e) {
var rawData = reader.result;
$.ajax({ url: data.puturl,
type: 'PUT',
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', progressHandlingFunction, false);
}
return myXhr;
},
success: completeHandler,
error: errorHandler,
// Form data
data: rawData,
cache: $.param(false),
contentType: "binary/octet-stream",
processData: $.param(false)
}, 'json');
};
这要简单得多,而且一切都很完美。然后后面下载数据的时候用一个带符号的url,我干脆把
ResponseContentDisposition: "attachment; filename="+fileData.name
作为 s3.getSignedUrl('getObject', params) 调用中的参数之一。
AND 在预先签名的 url 中检索文件,我把
ResponseContentDisposition: "attachment; filename="+fileData.name, 'ResponseContentType': fileData.type
负责确保浏览器期望收到的内容。
因为在使用预签名 url 时上传对象时无法设置内容类型,所以我还在服务器端添加了代码以在上传完成后更改对象内容类型。这是代码的核心:
var params = {
Bucket: 'sample',
CopySource: 'sample/' + file.key,
Key: file.key,
MetadataDirective: 'REPLACE',
ContentType: type
};
s3.copyObject(params, function (err, data){
if (err) {
console.log(err);
validationError(res, 'unable to change content-type!');
}
res.sendStatus(200);
});
这是一个最终正确的痛苦,我希望这会帮助其他人!
经过三天的追逐这个问题。是时候寻求帮助了。 我有一个签名 url 可以将文件上传到 Amazon S3。我知道这是正确的,因为 a
curl -v -T file.png --header "Content-Type:binary/octet-stream" "https://sample.s3.amazonaws.com/33d7e8f0-0fc5-11e5-9d95-2b3410860edd?AWSAccessKeyId=XXXXXXXX&Content-Type=binary%2Foctet-stream&Expires=1433984735&Signature=LUjj8iIAbCfNoskGhqLDhuEWVG4%3D"
正确成功。
但是我的 .ajax 上传代码(如下)使 S3 存储桶中的内容出现轻微乱码。
例如,如果我上传一个 .pdf 文件,它会从 S3 管理控制台正确加载,但如果它是 .png 或 .jpeg 等,它会失败......仔细查看文件长度错误(轻微)。
浏览器调用的核心是:
var formData = new FormData();
formData.append("upload", file);
$.ajax({ url: data.puturl,
type: 'PUT',
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', progressHandlingFunction,
false);
}
return myXhr;
},
success: completeHandler,
error: errorHandler,
data: formData,
cache: $.param(false),
contentType: "binary/octet-stream",
processData: $.param(false)
}, 'json');
这似乎行得通,但数据是乱码。我尝试将内容设置为 file.type 等,但无济于事。我需要在这里做一些编码吗?比如我缺少的base64????
如有任何见解,我们将不胜感激。
或者,如果有一种简单的方法可以不使用 .ajax 来做同样的事情,那就太好了。
根据 'tedder42' 上面提出的问题,以及更多的实验,我意识到发送 FormData 是问题所在。所以我将代码更改为仅使用 FileReader() 并传递原始数据。这非常有效。这是代码:
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function (e) {
var rawData = reader.result;
$.ajax({ url: data.puturl,
type: 'PUT',
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', progressHandlingFunction, false);
}
return myXhr;
},
success: completeHandler,
error: errorHandler,
// Form data
data: rawData,
cache: $.param(false),
contentType: "binary/octet-stream",
processData: $.param(false)
}, 'json');
};
这要简单得多,而且一切都很完美。然后后面下载数据的时候用一个带符号的url,我干脆把
ResponseContentDisposition: "attachment; filename="+fileData.name
作为 s3.getSignedUrl('getObject', params) 调用中的参数之一。
AND 在预先签名的 url 中检索文件,我把
ResponseContentDisposition: "attachment; filename="+fileData.name, 'ResponseContentType': fileData.type
负责确保浏览器期望收到的内容。
因为在使用预签名 url 时上传对象时无法设置内容类型,所以我还在服务器端添加了代码以在上传完成后更改对象内容类型。这是代码的核心:
var params = {
Bucket: 'sample',
CopySource: 'sample/' + file.key,
Key: file.key,
MetadataDirective: 'REPLACE',
ContentType: type
};
s3.copyObject(params, function (err, data){
if (err) {
console.log(err);
validationError(res, 'unable to change content-type!');
}
res.sendStatus(200);
});
这是一个最终正确的痛苦,我希望这会帮助其他人!