题 如何异步上传文件?


我想用jQuery异步上传一个文件。这是我的HTML:

<span>File</span>
<input type="file" id="file" name="file" size="10"/>
<input id="uploadbutton" type="button" value="Upload"/>

在这里我的 Jquery 码:

$(document).ready(function () {
    $("#uploadbutton").click(function () {
        var filename = $("#file").val();

        $.ajax({
            type: "POST",
            url: "addFile.do",
            enctype: 'multipart/form-data',
            data: {
                file: filename
            },
            success: function () {
                alert("Data Uploaded: ");
            }
        });
    });
});

我只获取文件名,而不是上传文件。我该怎么做才能解决这个问题?

当前解决方案

我正在使用 jQuery表单插件 上传文件。


2609
2017-10-03 10:22


起源


您只获取文件名,因为您的var文件名是$('#file')的值,而不是输入中的文件 - Jimmy
这是一个很好的: http://blueimp.github.io/jQuery-File-Upload/  - HTML5 ajax上传 - 为不支持的浏览器优雅地回退到iframe - 多文件异步上传我们已经使用过它并且效果很好。 (文档在这里) - Ashish Panery
jQuery Form Plugin似乎是最简单易用和跨浏览器兼容的方式......我是对的吗? - Lyth
检查一下: stackoverflow.com/questions/6974684/...,这里解释了如何通过jQuery实现它 - Chococroc
@Jimmy他怎么会得到输入中的文件呢? - alex


答案:


HTML5 您可以使用Ajax和jQuery进行文件上传。不仅如此,您还可以使用HTML5进度标记(或div)进行文件验证(名称,大小和MIME类型)或处理进度事件。最近我不得不制作文件上传器,但我不想使用  也没有iframe或插件,经过一些研究后我想出了解决方案。

HTML:

<form enctype="multipart/form-data">
    <input name="file" type="file" />
    <input type="button" value="Upload" />
</form>
<progress></progress>

首先,如果需要,您可以进行一些验证。例如,在文件的onChange事件中:

$(':file').on('change', function() {
    var file = this.files[0];
    if (file.size > 1024) {
        alert('max upload size is 1k')
    }

    // Also see .name, .type
});

现在,Ajax按下按钮提交:

$(':button').on('click', function() {
    $.ajax({
        // Your server script to process the upload
        url: 'upload.php',
        type: 'POST',

        // Form data
        data: new FormData($('form')[0]),

        // Tell jQuery not to process data or worry about content-type
        // You *must* include these options!
        cache: false,
        contentType: false,
        processData: false,

        // Custom XMLHttpRequest
        xhr: function() {
            var myXhr = $.ajaxSettings.xhr();
            if (myXhr.upload) {
                // For handling the progress of the upload
                myXhr.upload.addEventListener('progress', function(e) {
                    if (e.lengthComputable) {
                        $('progress').attr({
                            value: e.loaded,
                            max: e.total,
                        });
                    }
                } , false);
            }
            return myXhr;
        }
    });
});

正如您所看到的,使用HTML5(以及一些研究)文件上传不仅可以实现,而且非常简单。尝试一下 谷歌浏览器 因为每个浏览器都没有这些示例的某些HTML5组件。


2336
2018-01-06 13:34



我可以在upload.php中使用$ _FILES吗? - Alessandro Cosentino
这应该在Internet Explorer中工作,但只能在版本10中工作。(caniuse.com/xhr2) - Samir
在IE7-9中不起作用 - KevinDeus
嗨,我感谢PHP是您的首选语言...但我想知道您是否知道这是否也适用于ASP.NET MVC?我是.NET开发人员,我试图利用你的简单示例来做一些AJAX文件上传,但服务器端我没有得到我通过AJAX发布的文件。我正在使用最新的Chrome。 - Shumii
它的 FORMDATA 谁在这里做了所有的魔术。请务必查看这些文档 - 它涵盖了有关多个文件和字段的所有问题。 - incarnate


有关jQuery的文件上传有各种现成的插件。

做这种上传黑客并不是一种愉快的体验,因此人们喜欢使用现成的解决方案。

这里有几个:

您可以在NPM上搜索更多项目(使用“jquery-plugin”作为关键字)或在Github上搜索。


335
2017-10-15 10:35



AjaxFUP链接似乎被打破了。我怀疑这是指的是: valums.com/ajax-upload - UlfR
对于另一个读取的插件,总会有 Filepicker.io,它有点好处,它处理所有讨厌的大文件支持问题等。 - brettcvz
它实际上只有大约10行香草JS。这真的不是那么糟糕。 - mpen
现成的解决方案插件可能工作得很好,但是一段时间后你发现它不起作用,你认为它会没用,你不得不用不熟悉的脚本来破解它。所以,它是双向的。 - fletchsod
我可以用吗 JQuery File Uploader 多个视频..?它会支持..? - Mr world wide


2017年更新:它仍然取决于浏览器 你的 人口统计学用途。

使用“新”HTML5了解一件重要的事情 file API就是这样 IE 10之前不支持。如果您所针对的特定市场对旧版Windows的倾向高于平均水平,则可能无法访问它。

进入2017年,大约5%的浏览器是IE 6,7,8或9中的一个。如果你进入一家大公司(例如,这是一个B2B工具,或者你正在提供培训的东西),那么这个数字可能会爆炸。就在几个月前 - 在2016年 - 我在超过60%的机器上使用IE8处理了一家公司。

所以在你做任何事之前: 检查什么浏览器 你的 用户使用。如果你不这样做,你将学到一个快速而痛苦的教训,为什么“为我工作”对于客户的交付是不够的。

我的答案是从2008年开始的。


但是,有一些可行的非JS文件上传方法。您可以在页面上创建一个iframe(使用CSS隐藏),然后将表单定位到该iframe。主页不需要移动。

这是一个“真正的”帖子,所以它不是完全互动的。如果您需要状态,则需要服务器端进行处理。这根据您的服务器而有很大差异。 ASP.NET 有更好的机制。 PHP普通失败,但你可以使用 Perl的 或Apache修改以解决它。

如果您需要多个文件上传,最好一次执行一个文件(以克服最大文件上载限制)。将第一个表单发布到iframe,使用上面的内容监控其进度,完成后,将第二个表单发布到iframe,依此类推。

或者使用Java / Flash解决方案。他们对帖子的处理方式更加灵活......


237
2017-10-03 10:41



为了记录,如果浏览器支持File API,现在可以进行纯AJAX文件上传 - developer.mozilla.org/en/using_files_from_web_applications - meleyal
除非你需要IE9支持。 caniuse.com/fileapi - Oli
iframe解决方案非常简单,易于使用 - Matthew Lock
这是一个相当古老的答案,但它有点误导...... IE早在IE7支持XHR,并且早在IE5之前就通过ActiveX支持它。 w3schools.com/ajax/ajax_xmlhttprequest_create.asp。实现这一目标的实际方法当然是针对闪存(shockwave)组件,或推出Flash / ActiveX(Silverlight)控件。如果您可以通过javascript发起请求并处理响应,那么它就是ajax ..虽然,说过,ajax与xhr是同义词,但它本身并不描述传递/交换有效负载的下划线机制/组件。 - Brett Caswell
@BrettCaswell我并不是说AJAX / XHR是不可能的,只是因为不可能在IE上发布旧文件而不是永久版本的文件。那已经并且仍然完全正确。 - Oli


我推荐使用 精细上传 用于此目的的插件。你的 JavaScript 代码是:

$(document).ready(function() {
  $("#uploadbutton").jsupload({
    action: "addFile.do",
    onComplete: function(response){
      alert( "server response: " + response);
    }
  });
});

105
2017-11-21 16:38



它使用JSON - 因此对于PHP旧版本,它将无法使用。 - Lorenzo Manucci
看起来比Ajax文件上传更清晰,我需要包含一大段代码才能使用该死的东西。 - ripper234
现在是URL valums.com/ajax-upload。 - Patrick Fisher
“这个插件是在GNU GPL 2或更高版本以及GNU LGPL 2或更高版本下开源的。”因此,只要您不分发副本或修改版本,就不必打开项目。 - Trantor Liu
这是网站(fineuploader.com我现在发现,它是V4.2。 - Andrew_1510


注意:此答案已过时,现在可以使用XHR上传文件。


您无法使用上传文件 XMLHttpRequest的 (阿贾克斯)。您可以使用iframe或Flash模拟效果。优秀 jQuery表单插件 通过iframe发布文件以获得效果。


87
2017-10-03 10:36



是的,您可以POST到iframe并在那里捕获文件。我对此的经验非常有限,所以我无法对此发表评论。 - Mattias
小话:在Chrome和firefox的最新版本中,它是可能的, stackoverflow.com/questions/4856917/... - Alleo


这个 AJAX文件上传jQuery插件 上传文件somehwere,并传递 响应回调,没有别的。

  • 它不依赖于特定的HTML,只需给它一个 <input type="file">
  • 它不要求您的服务器以任何特定方式响应
  • 您使用的文件数量或页面上的位置无关紧要

- 使用尽可能少 -

$('#one-specific-file').ajaxfileupload({
  'action': '/upload.php'
});

- 或者多 -

$('input[type="file"]').ajaxfileupload({
  'action': '/upload.php',
  'params': {
    'extra': 'info'
  },
  'onComplete': function(response) {
    console.log('custom handler for file:');
    alert(JSON.stringify(response));
  },
  'onStart': function() {
    if(weWantedTo) return false; // cancels upload
  },
  'onCancel': function() {
    console.log('no file selected');
  }
});

81
2017-07-29 00:34



不适用于1.9.1:| - user840250
@ user840250 jQuery 1.9.1? - Jordan Feldstein


为未来的读者做好准备。

异步文件上传

使用HTML5

您可以上传文件 用jQuery 使用 $.ajax() 方法如果 FORMDATA 和 文件API 支持(HTML5功能)。

您也可以发送文件 没有FormData 但无论哪种方式,File API都必须以处理文件的方式处理文件 XMLHttpRequest的 (阿贾克斯)。

$.ajax({
  url: 'file/destination.html', 
  type: 'POST',
  data: new FormData($('#formWithFiles')[0]), // The form with the file inputs.
  processData: false,
  contentType: false                    // Using FormData, no need to process data.
}).done(function(){
  console.log("Success: Files sent!");
}).fail(function(){
  console.log("An error occurred, the files couldn't be sent!");
});

快速,纯粹的JavaScript(没有jQuery)例子见“使用FormData对象发送文件”。

倒退

不支持HTML5时(不 文件API)唯一的其他纯JavaScript解决方案(没有  或者任何其他浏览器插件) 隐藏的iframe 技术,允许模拟异步请求而不使用 XMLHttpRequest的 目的。

它包括使用文件输入将iframe设置为表单的目标。当用户提交请求并上传文件但响应显示在iframe内部而不是重新呈现主页面时。隐藏iframe使整个过程对用户透明并模拟异步请求。

如果操作正确,它应该在任何浏览器上虚拟工作,但它有一些警告如何从iframe获取响应。

在这种情况下,您可能更喜欢使用包装器插件 Bifröst 它使用的 iframe技术 还提供了一个 jQuery Ajax传输 允许 发送文件 只有 $.ajax() 像这样的方法:

$.ajax({
  url: 'file/destination.html', 
  type: 'POST',
  // Set the transport to use (iframe means to use Bifröst)
  // and the expected data type (json in this case).
  dataType: 'iframe json',                                
  fileInputs: $('input[type="file"]'),  // The file inputs containing the files to send.
  data: { msg: 'Some extra data you might need.'}
}).done(function(){
  console.log("Success: Files sent!");
}).fail(function(){
  console.log("An error occurred, the files couldn't be sent!");
});

插件

Bifröst 只是一个小包装器,它为jQuery的ajax方法添加了后备支持,但许多前面提到的插件都是如此 jQuery表单插件要么 jQuery文件上传 包括从HTML5到不同后备的整个堆栈以及一些有用的功能,以简化流程。根据您的需求和要求,您可能需要考虑裸实现或此插件中的任何一个。


75
2017-08-25 14:17



有一点需要注意,基于文档:您还应该发送 contentType: false。当我没有用chrome发送它时,表单内容类型被jQuery无效。 - ash
很好的答案。一些改进建议:删除与答案无关的代码部分,例如 .done() 和 .fail() 回调。另外,一个不使用的例子 FormData 并且一份优惠/缺点清单会很棒。 - Zero3
我收到了这个错误: TypeError: Argument 1 of FormData.constructor does not implement interface HTMLFormElement. - candlejack


我一直在使用下面的脚本来上传恰好工作的图像。

HTML

<input id="file" type="file" name="file"/>
<div id="response"></div>

JavaScript的

jQuery('document').ready(function(){
    var input = document.getElementById("file");
    var formdata = false;
    if (window.FormData) {
        formdata = new FormData();
    }
    input.addEventListener("change", function (evt) {
        var i = 0, len = this.files.length, img, reader, file;

        for ( ; i < len; i++ ) {
            file = this.files[i];

            if (!!file.type.match(/image.*/)) {
                if ( window.FileReader ) {
                    reader = new FileReader();
                    reader.onloadend = function (e) {
                        //showUploadedItem(e.target.result, file.fileName);
                    };
                    reader.readAsDataURL(file);
                }

                if (formdata) {
                    formdata.append("image", file);
                    formdata.append("extra",'extra-data');
                }

                if (formdata) {
                    jQuery('div#response').html('<br /><img src="ajax-loader.gif"/>');

                    jQuery.ajax({
                        url: "upload.php",
                        type: "POST",
                        data: formdata,
                        processData: false,
                        contentType: false,
                        success: function (res) {
                         jQuery('div#response').html("Successfully uploaded");
                        }
                    });
                }
            }
            else
            {
                alert('Not a vaild image!');
            }
        }

    }, false);
});

说明

我用回应 div 上传完成后显示上传动画和响应。

最好的部分是,当您使用此脚本时,您可以使用该文件发送额外的数据,如ids等。我已经提到了 extra-data 如在脚本中。

在PHP级别,这将作为普通文件上载。额外数据可以检索为 $_POST 数据。

在这里你没有使用插件和东西。您可以根据需要更改代码。你不是在这里盲目编码。这是任何jQuery文件上传的核心功能。实际上是Javascript。


57
2018-01-25 11:03



-1使用jQuery而不使用它的选择器引擎和事件处理程序。 addEventListener 不是跨浏览器。 - Mark
因为添加一个单独的答案是毫无意义的,这个答案主要基于这个答案,只需要做一些改动。相反,应该纠正这个答案。 - Mark
@RainFromHeaven,拜托,你能编辑答案吗?我不知道如何以跨浏览器的方式做到这一点。 - Thiago Negri
仍然无法在IE 9中运行。分配用户仍然使用那些版本的IE。 - Pierre
有人可以解释如何在asp.net中工作?我使用webmethod吗?如果是的话会是什么样子? - Arbaaz