【问题标题】:Is it possible to upload file via $.ajax(options) or xhr.send(file) only?是否可以仅通过 $.ajax(options) 或 xhr.send(file) 上传文件?
【发布时间】:2011-08-31 18:12:46
【问题描述】:

我正在使用文件 api 和 xhr2 规范。我创建了一个使用FormData$.ajax(options) 的上传器(由旧浏览器支持的flash),其中带有File 的FormData 对象是options.data 对象的一部分。一切正常。

现在我决定删除FormData,因为浏览器支持较弱。除了

之外,我想不出一种上传文件的方法
var xhr = new XMLHttpRequest();
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.setRequestHeader("X-File-Name", file.name);
xhr.send(file);

它不会返回我可以在递归函数中使用的 Promise。

我的代码是这样的:

   startUpload: function() {
        var that = this;
        that.recurseSend(that.queue);       
    },

    _initProgressListener: function (options, file) {
        var that = this;
        var xhr = $.ajaxSettings.xhr();
        options.contentType = 'multipart/form-data';        
        options.processData = false;
        options.type = 'POST';
        // WHAT TO DO HERE TO avoid FormData???? What ever I put into options.data - fails

        /* THIS WOULD WORK
        var formData = new FormData();
        formData.append('file', file);
        options.data = formData;
        */            

        if (xhr.upload && xhr.upload.addEventListener) {
            xhr.upload.addEventListener('progress', function (e) {
                that._onProgress(e, file);
            }, false);
            options.xhr = function () {
                return xhr;
            };
        }
    }, 

    recurseSend: function (queue) { 
        var file = queue.pop();
        if(file != undefined) {
            var that = this;
            var options = that.options;    
            that._initProgressListener(options, file);

            var send = function() {
                jqXHR = ($.ajax(options)).done(function(result, textStatus, jqXHR) {
                        that._onDone(result, textStatus, jqXHR, file);
                        queue.stats['successful_uploads']++;
                    }).fail(function(jqXHR, textStatus, errorThrown) {
                        that._onFail(jqXHR, textStatus, errorThrown, file);
                        queue.stats['upload_errors']++;
                    }).always(function(result, textStatus, jqXHR) {
                        that._onAlways(result, textStatus, jqXHR, file);
                        queue.stats['files_queued']--;
                        that.recurseSend(queue);
                    });
                    return jqXHR;
            };

            this._beforeSend(file);              
            return send();
        }
    },

简而言之,$.ajax(options) 解析为 xhr.send(formData) 如果 options.data = FormData 但我如何使其解析为 xhr.send(file)

已编辑:我正在玩它,如果我设置 options.data = file;然后 $.ajax(options) 执行 xhr.send(theFile);但有错误Error: INVALID_STATE_ERR: DOM Exception 11

请求作为 POST multipart/form-data 请求发送,但没有包含文件的多部分正文

如果我把它放到options.data = {file: file}; 中,无论processData 属性是否设置为true,它都会被序列化。

【问题讨论】:

    标签: javascript jquery ajax html file-upload


    【解决方案1】:

    How can I upload files asynchronously?

    如果不通过 iFrame,您似乎无法做到这一点。我链接的答案中似乎有工作的 sn-ps,并且有几个插件可以为你做。

    * 编辑,因为我得到了 cmets *

    是的,这是可能的-http://caniuse.com/xhr2-虽然没有低于 10 的 IE 支持..

    这是一个教程:

    http://www.html5rocks.com/en/tutorials/file/xhr2/

    http://www.profilepicture.co.uk/ajax-file-upload-xmlhttprequest-level-2/

    【讨论】:

    • 对不起,我问这种方式是否可行。它适用于 xhr.send(formData);让它解析为 xhr.send(file) 只是一个正确设置的问题。就是不知道怎么弄,调试的时候很难找到。
    • 是的。 S0 据我所知,使用 ajax 你不能上传文件。但是,您可以使用 iframe 或 flash 向用户显示它正在以 ajaxy 方式完成。
    • 您可以使用 Formdata 以及使用文件,就像 lisa 尝试做的那样,但我相信 jQuery 并不支持它。甚至还有一个例子:hacks.mozilla.org/2009/06/…
    • 这个(和链接的问题)具有误导性,您可以通过 ajax/xhr2 上传文件 - 当然取决于浏览器的支持
    【解决方案2】:

    您可以从使用FileReader 或类似 API 读取的 HTML5 文件数据手动生成上传的 MIME 数据。签出:https://github.com/coolaj86/html5-formdata。这将或多或少地做到这一点,尽管它取决于getAsBinary() - 将其更改为也能够使用FileReaderreadAsBinaryString() 可能会更加跨浏览器兼容。

    请注意,这在 IE7/8 中仍然无法正常工作,正如其他人所说,如果不求助于 Flash 或 iframe,就无法做到这一点。话虽这么说,如果您使用的是 File,想必您并不关心 IE7 或 IE8...

    【讨论】:

    • 谢谢,很高兴知道这一点。如果我没有 Flash 支持,我不会使用它。你说得对,我不关心 IE 用户,在 Linux 上运行了 5 年后......有时我只是告诉他们用另一个浏览器运行我的应用程序......
    【解决方案3】:

    我自己使用了 valums ajax 上传器。你可以从这里得到它: http://valums.com/ajax-upload/。它工作得很好。我不知道确切的实现细节,但这里有一个非常简短的描述:

    “这个插件在 FF3.6+、Safari4+、Chrome 中使用 XHR 上传多个带有进度条的文件,并在其他浏览器中回退到基于隐藏 iframe 的上传,在任何地方提供良好的用户体验。”

    所以听起来它非常接近你想要的。这是从服务器的角度(来自 server/readme.txt)描述其工作方式的另一条信息:

    1. 对于 IE6-8、Opera 和其他旧版本的浏览器,您获取的文件为 您通常使用常规的基于表单的上传。

    2. 对于使用进度条上传文件的浏览器,您需要获取原始文件 发布数据并将其写入文件。

    所以它需要在服务器端进行特殊处理。幸运的是,它带有几个参考服务器端实现(perl、php 和 java),所以不应该太麻烦。快乐的 ajax 上传:)

    【讨论】:

    • Timo,我可以在几个小时内创建这样一个上传器,完全根据我的需要。我认为程序员最大的问题是他们需要一些代码,而要做的第一件事就是在谷歌周围搜索其他人的解决方案:-) 我明白,如果一些通用库提供低级支持。但不是在文件上传器的情况下。毕竟,当你遇到问题时,你会花更多的时间进行逆向工程,如果你是自己创造的...... :-)
    • 真的吗?好吧,我不是那么多 javascript 大师,我可以。绝对不是在不同浏览器中运行良好的东西。但我想如果你真的知道自己在做什么,那么写出 683 行 javascript 并不是什么大不了的事(包括 cmets)。无论如何,我看不到启用 ajax 上传的基础设施不是低级别的,为什么我需要在任何项目中触及这些东西。在考虑什么构成“提供低级支持的通用库”时,我想 YMMV。
    • @Sloin 我完全不同意。如果您查看github.com/blueimp/jQuery-File-Upload/blob/master/js/… ex 之类的来源。第 62 行(至少在今天 :P )你可以看到为了使这些东西兼容,你必须经历多少垃圾。
    【解决方案4】:

    每当您处理从用户机器上传任意数据时,答案通常是“不,如果可以,那是一个错误”。

    这让我觉得它属于违反安全规定的范畴。您不能更改文件输入控件的值或对其执行许多其他操作,包括读取文件的真实路径或其内容。此外,在某些平台上,您甚至没有文件大小(IE,我在看着您)而没有弹出一些安全对话框(通过 activex 控件)。鉴于所有这些问题,我可能会想说,即使您确实找到了解决方案,它也可能在未来被视为错误并被删除或更改。

    换句话说,我认为这不是一件安全的事情,除非你找到一个明确支持它的知名来源......比如 chromium 开发博客。

    【讨论】:

    • 太棒了!我不知道这些。我指的是您可以在此处看到的攻击 bit.ly/mmKsKj 和此处的建议 bit.ly/igcrvH 。许多 w3c 建议在漏洞暴露后从未得到实施或被合法删除:mzl.la/fBAMxD。因此,尽管存在这些草案,但我认为必须考虑到与此功能相关的漏洞历史,以确定是否可以依赖或将实施此功能;这就是为什么我特别尊重浏览器组而不是 w3c。
    • 恐怕我对此投了反对票,因为它不准确。事实上,XHR2、FormData、File、FileReader 和类似的 API 已经被 Chrome、Firefox 甚至 IE9/10 实现了一段时间,并且仍然依赖于用户对文件的选择。特别是,当用户必须显式选择文件时,通过启用直接访问不会增加真正的安全漏洞,而不是迫使 Web 开发人员跳过将文件上传到服务器的过程,然后才能继续阅读客户端。
    • 虽然我在理论上同意你的观点,但攻击的创新总是让我感到惊讶,依靠一项技术的闪亮新功能将是一种讽刺你会惊讶地发现,清晰的模式还在继续。
    猜你喜欢
    • 1970-01-01
    • 2019-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-22
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    相关资源
    最近更新 更多