直接上传到 AWS S3 : SignatureDoesNotMatch only for IE
Direct uploading to AWS S3 : SignatureDoesNotMatch only for IE
我使用 Amazon Web Service S3 上传和存储我的文件。由于这个预签名 url,我使用 AWS Sdk 为 Node.js server-side 生成了预签名 url 以直接从浏览器上传文件。
工作原理
Server-side 我有一个方法 returns pre-signed url.
AWS.config.loadFromPath(__dirname + '/../properties/aws-config.json');
AWS.config.region = 'eu-west-1';
//Credentials are loaded
var s3 = new AWS.S3();
var docId = req.query.doc;
var params = {
Bucket: res.locals.user.bucketId,
Key: docId+"."+req.query.fileExtension,
ACL : "bucket-owner-read",
ContentType : req.query.fileType
};
s3.getSignedUrl('putObject', params, function (err, url) {
if(url){
res.writeHead(200);
var result = {
AWSUrl : url
};
//Generates pre signed URL with signature param
res.end(JSON.stringify(result));
}
}
我直接上传我的文件到S3 client-side
var loadToAWSS3 = function(url, file, inputFileId){
var data = new FormData();
data.append('file', file);
$.ajax({
url: url,//url getted from server-side method
type: 'PUT',
data : data,
headers: {
'Content-Type': file.type
},
processData: false,
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){
myXhr.upload.addEventListener('progress',function(e){
if(e.lengthComputable){
var max = e.total;
var current = e.loaded;
var percentage = (current * 100)/max;
//stuff to handle progress...
}
},
false);
}
return myXhr;
},
statusCode: {
200: function () {
//some stuff
}
});
}
Chrome & Firefox 行为
按预期工作,预签名 url 已获取,然后文件已上传,我可以在我的 AWS S3 控制台中看到它。
可爱的IE 11
SignatureDoesNotMatch 错误! IE 向 Content-Type 请求 header 添加了一些 AWS 不期望的额外内容,这会导致签名比较出错。 Server-side,Sdk根据:
生成签名
ContentType : req.query.fileType //(something like application/pdf)
而当我使用 IE 调试器检查请求时,我看到
Content-Type application/pdf, multipart/form-data; boundary=---------------------------7df2f3283091c
在Chrome我的要求header没问题
Content-Type: application/pdf
我怎样才能删除这个 IE extra Content-Type?如果不可能,我如何在发送请求之前生成这些额外的东西,以便在签名中获得 pre-signed url 和额外的东西?
好的,我终于想通了。
使用 FormData() 模拟您通过表单发送文件。这就是为什么 IE 总是添加
multipart/form-data; boundary=---------------------------7**********
为了解决这个问题,我使用原始 Javascript 和 XMLHttpRequest 感谢 this answer
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open('PUT', url, true);
xmlHttpRequest.setRequestHeader('Content-Type', file.type);
xmlHttpRequest.send(file);
它适用于 Chrome、Firefox、IE 11(我没有测试过 IE<11,但根据 W3Schools 它适用于 IE7+)。 IE 不再有额外的内容类型。
希望对您有所帮助
如果您可以访问 xhr,您可以执行以下操作:
var _send = xhr.send;
xhr.send = function() {
_send.call(xhr, file);
}
我使用 Amazon Web Service S3 上传和存储我的文件。由于这个预签名 url,我使用 AWS Sdk 为 Node.js server-side 生成了预签名 url 以直接从浏览器上传文件。
工作原理
Server-side 我有一个方法 returns pre-signed url.
AWS.config.loadFromPath(__dirname + '/../properties/aws-config.json');
AWS.config.region = 'eu-west-1';
//Credentials are loaded
var s3 = new AWS.S3();
var docId = req.query.doc;
var params = {
Bucket: res.locals.user.bucketId,
Key: docId+"."+req.query.fileExtension,
ACL : "bucket-owner-read",
ContentType : req.query.fileType
};
s3.getSignedUrl('putObject', params, function (err, url) {
if(url){
res.writeHead(200);
var result = {
AWSUrl : url
};
//Generates pre signed URL with signature param
res.end(JSON.stringify(result));
}
}
我直接上传我的文件到S3 client-side
var loadToAWSS3 = function(url, file, inputFileId){
var data = new FormData();
data.append('file', file);
$.ajax({
url: url,//url getted from server-side method
type: 'PUT',
data : data,
headers: {
'Content-Type': file.type
},
processData: false,
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){
myXhr.upload.addEventListener('progress',function(e){
if(e.lengthComputable){
var max = e.total;
var current = e.loaded;
var percentage = (current * 100)/max;
//stuff to handle progress...
}
},
false);
}
return myXhr;
},
statusCode: {
200: function () {
//some stuff
}
});
}
Chrome & Firefox 行为
按预期工作,预签名 url 已获取,然后文件已上传,我可以在我的 AWS S3 控制台中看到它。
可爱的IE 11
SignatureDoesNotMatch 错误! IE 向 Content-Type 请求 header 添加了一些 AWS 不期望的额外内容,这会导致签名比较出错。 Server-side,Sdk根据:
生成签名ContentType : req.query.fileType //(something like application/pdf)
而当我使用 IE 调试器检查请求时,我看到
Content-Type application/pdf, multipart/form-data; boundary=---------------------------7df2f3283091c
在Chrome我的要求header没问题
Content-Type: application/pdf
我怎样才能删除这个 IE extra Content-Type?如果不可能,我如何在发送请求之前生成这些额外的东西,以便在签名中获得 pre-signed url 和额外的东西?
好的,我终于想通了。
使用 FormData() 模拟您通过表单发送文件。这就是为什么 IE 总是添加
multipart/form-data; boundary=---------------------------7**********
为了解决这个问题,我使用原始 Javascript 和 XMLHttpRequest 感谢 this answer
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open('PUT', url, true);
xmlHttpRequest.setRequestHeader('Content-Type', file.type);
xmlHttpRequest.send(file);
它适用于 Chrome、Firefox、IE 11(我没有测试过 IE<11,但根据 W3Schools 它适用于 IE7+)。 IE 不再有额外的内容类型。
希望对您有所帮助
如果您可以访问 xhr,您可以执行以下操作:
var _send = xhr.send;
xhr.send = function() {
_send.call(xhr, file);
}