Javascript FormData()文件上传到S3适用于Chrome,但不适用于Safari

时间:2017-01-19 07:02:07

标签: javascript file-upload amazon-s3 safari

在Web应用程序上工作时,我将图像文件从浏览器直接转到S3存储桶。这适用于Chrome,但在Safari中没有错误,但代码最终会将空文件上传到S3存储桶。一切基本上看起来都适用于Safari,S3服务器甚至返回204成功的http响应,文件看起来像在桶中(但是大小为0字节)。

我进行了调试,blobData在Chrome中的大小为55747,但在Safari中只有大小47560用于同一图像。另外,我发现在网络部分开发工具中看起来略有不同:

Chrome - 正在工作(204响应的正面大小为~534B):

enter image description here

Safari - 不使用空文件(大小列只显示虚线)

enter image description here

这是JS上传代码:

    function uploadFile(data_url, s3Data, url, filename, id, thumbnail_url){
        var xhr = new XMLHttpRequest();
        xhr.open("POST", s3Data.url);

        var postData = new FormData();
        for(key in s3Data.fields){
            postData.append(key, s3Data.fields[key]);
        }

        var blobData = dataURItoBlob(data_url);

        postData.append('file', new File([blobData], filename));

        xhr.onreadystatechange = function() {
            if(xhr.readyState === 4){
                if(xhr.status === 200 || xhr.status === 204){
                    setTimeout(function(){

                        $('#photo_container').append('<div id="image_container_'+id+'" class="hover-card mdl-cell--3-col-desktop mdl-cell--2-col-tablet mdl-cell--2-col-phone mdl-shadow--2dp"></div>');

                        $('.star-image').unbind('click').click( star_image_click );
                        $('.close-image').unbind('click').click(remove_image_click);
                        loading_files -= 1;
                        if ( loading_files == 0 ) {
                            $('#photo_load_spinner').removeClass('is-active');
                            $('#photo_load_text').text("");
                        }else{
                            $('#photo_load_text').text(loading_files+" files loading.  Please wait.");
                        }

                    }, 1000);


                }else{
                    alert("Could not upload file. "+xhr.responseText);
                }
            }
        };
        xhr.send(postData);
    }

    function dataURItoBlob(dataURI) {
        var binary = atob(dataURI.split(',')[1]);
        var array = [];
        for(var i = 0; i < binary.length; i++) {
            array.push(binary.charCodeAt(i));
        }
        return new Blob([new Uint8Array(array)], {type: 'image/png'});
    }

我有点不知道下一步要找什么。任何帮助将不胜感激。谢谢!

修改

请注意,我应该提供更多信息。 data_url是从canvas元素生成的,我用它在浏览器中调整图像大小,虽然我已经确认画布在上传之前在safari中正确显示图像。这是代码:

    function ResizeFile(raw_file) {

        var reader = new FileReader();
        reader.onload = function(e) {
            var img = document.createElement("img");

            img.onload = function() {

                var canvas = document.createElement('canvas');

                var ctx = canvas.getContext("2d");
                //ctx.drawImage(img, 0, 0);

                var MAX = 1200;
                var width = img.width;
                var height = img.height;

                if (width > height) {
                  if (width > MAX) {
                    height *= MAX / width;
                    width = MAX;
                  }
                } else {
                  if (height > MAX) {
                    width *= MAX / height;
                    height = MAX;
                  }
                }
                canvas.width = width;
                canvas.height = height;
                ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, width, height);

                var dataurl = canvas.toDataURL("image/png");

                getSignedRequest(dataurl);

            }

            img.src = e.target.result;

        }
        reader.readAsDataURL(raw_file);
    }

2 个答案:

答案 0 :(得分:3)

我们可以调整图像文件的大小并上传到服务器。在Chrome和Safari上测试,两者都可以。

fileChange() {

    var fileInputTag = document.getElementById("myFile");

    if ('files' in fileInputTag) {
        if (fileInputTag.files.length > 0) {

            var file = fileInputTag.files[0];

            var type = 'image/jpeg',
            maxWidth = 800,
            maxHeight = 600,
            quality = 0.5,
            ratio = 1,

            canvas = document.createElement('canvas'),
            context = canvas['getContext']('2d'),
            canvasCopy = document.createElement('canvas'),
            copyContext = canvasCopy.getContext('2d'),

            img = new Image();

            img.onload = function () {
              if (img.width > maxWidth) {
                ratio = maxWidth / img.width;
              } else if (img.height > maxHeight) {
                ratio = maxHeight / img.height;
              }

              canvasCopy.width = img.width;
              canvasCopy.height = img.height;
              copyContext.drawImage(img, 0, 0);
              canvas.width = img.width * ratio;
              canvas.height = img.height * ratio;
              context.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvas.width, canvas.height);

              canvas.toBlob((blob) =>  {
                blob['name'] = file.name.split('.')[0] + '.jpeg';

                var formData:FormData = new FormData();
                formData.append('uploadFile', blob, blob.name);

                // do upload here

              }, type, quality);

            };

            img.src = URL.createObjectURL(file);

        }
    }
}

将此添加到index.html或在上面的脚本执行之前执行

if (!HTMLCanvasElement.prototype.toBlob) {
    Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
    value: function (callback, type, quality) {

        var binStr = atob( this.toDataURL(type, quality).split(',')[1] ),
            len = binStr.length,
            arr = new Uint8Array(len);

        for (var i = 0; i < len; i++ ) {
        arr[i] = binStr.charCodeAt(i);
        }

        callback( new Blob( [arr], {type: type || 'image/png'} ) );
    }
    });
}

答案 1 :(得分:1)