Safari converts File to [object Object] when inserted into FormData. How to fix?

核能气质少年 提交于 2020-01-13 03:12:24

问题


I'm posting a file in Javascript using the new FormData interface. When I send a file using Safari 5.1.5 using "multipart/form-data", Safari coerces the File into a string, and instead of sending the actual file contents, it sends [object Object].

Example:

var formdata = new FormData();
formdata.append("file", file);
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://example.com/upload", true);
xhr.send(formdata);

What Safari ends up sending:

Origin: https://example.com/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.5 Safari/534.55.3
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarycLc5AIMWzGxu58n8
Referer: https://example.com/upload

------WebKitFormBoundarycLc5AIMWzGxu58n8
Content-Disposition: form-data; name="file"

[object Object]

My file is therefore uploaded, but the contents of the file are, you guessed it, [object Object].

What in the world is going on here? Is this a Safari bug?

Edit 1

For those curious how to dynamically generate a JS Blob, here's an example:

var Builder = (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder);
var builder = new Builder();
builder.append("hello, world");
var file = builder.getBlob("text/plain")

Unfortunately this does not work on Safari, so it didn't really help to include it in the question.

Edit 2

The file object I reference is from a drop action on a DOM element. Here's an example for how to retrieve a file. Run the following after the DOM has loaded.

function cancel(e) {
    if (e.stopPropagation) {
        e.stopPropagation();
    }
    if (e.preventDefault) {
        e.preventDefault();
    }
}

function drop(e) {
    cancel(e);
    for (var i=0; i<e.dataTransfer.files.length; i++) {
        file = e.dataTransfer.files[i];
    }
}

var elem = document.getElementById("upload-area");
elem.addEventListener("drop", drop, false);

回答1:


This didn't seem relevant when I was asking the question, but I figured this one out. Before uploading the file using XMLHttopRequest, I called jQuery's $.ajax method to call an endpoint in our backend to prep the file.

In short: this is a bug in jQuery on Safari. I was using a for loop to process a list of files, and upload them. I passed a file object as a parameter to the jQuery $.ajax method so that the file object I wanted wouldn't be rewritten as multiple loops were executed. E.g.

for (i in files) {
    var file = files[i];
    $.ajax({
        method: "POST",
        myFile: file,
        success: function(response) {
            var file = this.myFile;
            // ...
    });
}

Turns out that jQuery happens to clone the file object incorrectly in Safari. So instead of casting it to a file when set to this.myFile, it casts it into an object, thus making it lose all of its special "file-like" capabilities. The other browsers appear to understand that the object is still a file despite this.

The answer is to write a callback method to handle the file uploads.

function handleFile(file) {
    $.ajax({
        method: "POST",
        success: function(response) {
            // ...
    });
}

for (var i in files) {
    handleFile(files[i]);
}

P.S. Going to file this to the jQuery bug tracker, but just wanted to keep this here in case anyone else has the same issue.




回答2:


file needs to be a String, otherwise if it's an Object its toString() method gets called when you append it to the form data object.

This is directly related to Blob not working in Safari. In order to get this working in Safari you would need a way to coerce the file into a String yourself, which obviously isn't the easiest thing to do (don't even know if it's possible for security reasons?).



来源:https://stackoverflow.com/questions/9951531/safari-converts-file-to-object-object-when-inserted-into-formdata-how-to-fix

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!