【问题标题】:Safari converts File to [object Object] when inserted into FormData. How to fix?Safari 在插入 FormData 时将 File 转换为 [object Object]。怎么修?
【发布时间】:2012-04-14 15:26:56
【问题描述】:

我正在使用新的 FormData 接口在 Javascript 中发布文件。当我使用 Safari 5.1.5 使用“multipart/form-data”发送文件时,Safari 将文件强制转换为字符串,而不是发送实际文件内容,而是发送 [object Object]

例子:

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

Safari 最终发送的内容:

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]

我的文件因此被上传,但文件的内容,你猜对了,[object Object]

这里到底发生了什么?这是 Safari 的错误吗?

编辑 1

对于那些好奇如何动态生成 JS Blob 的人,这里有一个例子:

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

不幸的是,这在 Safari 上工作,所以将它包含在问题中并没有真正帮助。

编辑 2

我引用的文件对象来自对 DOM 元素的拖放操作。这是如何检索文件的示例。在 DOM 加载后运行以下命令。

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);

【问题讨论】:

  • 需要在第 2 行查看定义 file 变量的代码。
  • file 由拖放操作提供。它不是动态创建的。在其他浏览器中,您可以动态构建 Blob,但 Safari 还不能这样做。
  • 问题已更新,代码解释了我如何获得file 对象。
  • 只需将这个确切的代码放在我服务器上一个快速而肮脏的页面上,它似乎可以正常工作。它只是将帖子发布到一个 PHP 文件,该文件将上传内容放入一个临时目录,然后读取其内容并将其回显。 kevincennis.com/uploadtest.
  • 哇——它确实有效。情节变厚了。这一定与我忽略的问题有关(我认为它不相关......我认为它现在是)。我通过 postMessage 将文件发送到接收 drop 的页面内的 iframe。 iframe 包含在收到 postMessage 之前进行侦听、创建 FormData,然后发布到 URL 的脚本。

标签: javascript safari uploading


【解决方案1】:

当我问这个问题时,这似乎并不相关,但我想出了这个问题。在使用 XMLHttopRequest 上传文件之前,我调用了 jQuery 的 $.ajax 方法来调用后端中的端点来准备文件。

简而言之:这是 Safari 上的 jQuery 中的一个错误。我正在使用 for 循环来处理文件列表并上传它们。我将一个文件对象作为参数传递给 jQuery $.ajax 方法,这样我想要的文件对象就不会在执行多个循环时被重写。例如

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

原来 jQuery 碰巧在 Safari 中错误地克隆了 file 对象。因此,当设置为this.myFile 时,它不会将其转换为文件,而是将其转换为对象,从而使其失去所有特殊的“类文件”功能。尽管如此,其他浏览器似乎明白该对象仍然是一个文件。

答案是写一个回调方法来处理文件上传。

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

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

附:打算将此文件提交给 jQuery 错误跟踪器,但只是想将其保留在此处,以防其他人遇到同样的问题。

【讨论】:

    【解决方案2】:

    file 必须是 String,否则如果是 Object,则在将其附加到表单数据对象时会调用其 toString() 方法。

    这与 Blob 在 Safari 中不工作直接相关。为了让它在 Safari 中正常工作,您需要一种方法自己将文件强制转换为 String,这显然不是最简单的事情(出于安全原因,甚至不知道这是否可行?)。

    【讨论】:

    • 是的,没有完整的 blob 支持是不可能的。但是,在 WebKit、Chrome 和 Firefox 中,您可以调用文件的 slice 方法来检索特定字节(对于分段上传很有用)。另外,我刚刚意识到我遗漏了问题的一个关键部分——我上传的文件是通过 iframe 中的 postMessage 接收的。
    • 另外,我假设和你一样,但是当你在文件对象上调用toString() 时,它会被强制转换为[object File],而不是[object Object]
    猜你喜欢
    • 2019-06-10
    • 2012-12-27
    • 1970-01-01
    • 1970-01-01
    • 2019-09-07
    • 2014-05-09
    • 2012-06-03
    • 1970-01-01
    • 2016-04-14
    相关资源
    最近更新 更多