直接上传到AWS S3:SignatureDoesNotMatch仅适用于IE。

问题描述 投票:3回答:2

我使用亚马逊网络服务S3来上传和存储我的文件,我用AWS Sdk为Node.js服务器端生成一个预签名的url,直接从浏览器上传文件,感谢这个预签名的url。我使用AWS Sdk for Node.js服务器端生成一个预签名的url,通过这个预签名的url直接从浏览器上传文件。

它是如何工作的

服务器端我有一个方法,返回预签名的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客户端。

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请求头中添加了一些AWS没有预料到的额外内容,导致签名比较错误。在服务器端,Sdk根据.NET协议生成签名,而当我用IE调试器检查请求时,我看到的是.NET协议。

ContentType : req.query.fileType //(something like application/pdf)

而当我用IE调试器检查该请求时,我看到的是

 Content-Type   application/pdf, multipart/form-data; boundary=---------------------------7df2f3283091c

在Chrome浏览器中,我的请求头是好的

Content-Type: application/pdf

如何才能删除这个IE额外的Content-Type?如果不可能的话,我如何在发送请求之前生成这个额外的东西,以便在签名中获得带有额外东西的预签名网址?

javascript ajax node.js internet-explorer amazon-s3
2个回答
10
投票

好了,我终于明白了。

使用FormData()可以模拟你通过表单发送文件。这就是为什么IE总是添加

multipart/form-data; boundary=---------------------------7**********

为了解决这个问题,我使用原始的Javascript与XMLHttpRequest感谢 本回答

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下不再有额外的内容类型。

希望能帮到你


0
投票

如果你能访问Xhr,你可以做。

var _send = xhr.send;
xhr.send = function() {
  _send.call(xhr, file);
}
© www.soinside.com 2019 - 2024. All rights reserved.