关于javascript:如何异步上传文件?

How can I upload files asynchronously?

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

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

这里是我的EDCOX1代码0代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$(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表单插件上载文件。


使用HTML5,可以用Ajax和jQuery进行文件上传。不仅如此,您还可以进行文件验证(名称、大小和MIME类型),或者使用HTML5进度标签(或DIV)处理进度事件。最近,我不得不做一个文件上传,但我不想使用Flash或iFrAMS或插件,并经过一些研究,我想出了解决方案。

HTML:

1
2
3
4
5
<form enctype="multipart/form-data">
    <input name="file" type="file" />
    <input type="button" value="Upload" />
</form>
<progress></progress>

首先,如果需要的话,可以做一些验证。例如,在文件的EDCOX1×0事件中:

1
2
3
4
5
6
7
8
9
$(':file').on('change', function () {
  var file = this.files[0];

  if (file.size > 1024) {
    alert('max upload size is 1k');
  }

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

现在,EDOCX1的"1"提交按钮的点击:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
$(':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(和一些研究)文件上传不仅成为可能,而且非常容易。尝试使用谷歌Chrome,因为示例中的某些HTML5组件在每个浏览器中都不可用。


2019年更新:这仍然取决于你的人口统计使用的浏览器。

要理解"新"HTML5 fileAPI的一个重要问题是,直到IE 10才支持它。如果您所瞄准的特定市场对旧版本的Windows具有高于平均水平的预紧度,那么您可能无法访问它。

截至2017,约5%的浏览器是IE 6, 7, 8或9之一。如果你进入一个大公司(例如,这是一个B2B工具,或者你正在为培训提供的东西),这个数字可能会增加。在2016,我处理了一个公司使用IE8超过60%的机器。

这是2019,因为这个编辑,几乎11年后,我的第一个答案。IE9和Lead都在1%的全球范围内,但仍然有更高的使用集群。

重要的是,不管它的特性是什么,检查你的用户使用什么浏览器。如果你不这样做,你会学到一个快速而痛苦的教训:为什么"为我工作"在交付给客户的过程中是不够好的。CANIUE是一个有用的工具,但请注意他们从哪里得到人口统计。他们可能与你的不一致。这从来都不比企业环境更真实。

我2008年的回答如下。

但是,有一些可行的非JS文件上载方法。您可以在页面上创建一个iframe(用css隐藏),然后以表单为目标发布到该iframe。主页不需要移动。

这是一个"真实"的帖子,所以它不是完全交互式的。如果您需要状态,您需要一些服务器端的东西来处理它。这在很大程度上取决于您的服务器。ASP.NET有更好的机制。php-plain失败,但您可以使用perl或apache修改来绕过它。

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

或者使用Java/Flash解决方案。他们可以灵活地处理自己的职位…


为此,我建议使用优秀的上载程序插件。您的JavaScript代码为:

1
2
3
4
5
6
7
8
$(document).ready(function() {
  $("#uploadbutton").jsupload({
    action:"addFile.do",
    onComplete: function(response){
      alert("server response:" + response);
    }
  });
});


注意:这个答案已经过时了,现在可以使用xhr上传文件。

不能使用xmlhttprequest(ajax)上载文件。可以使用iframe或flash模拟效果。通过iframe发布文件以获得效果的优秀jquery表单插件。


为将来的读者做总结。

异步文件上传用HTML5

如果支持formdata和文件API(两个html5功能),则可以使用$.ajax()方法通过jquery上载文件。

您也可以发送不带FormData的文件,但无论采用哪种方式,文件API都必须存在,以处理文件,并且可以使用XMLHttpRequest(Ajax)发送这些文件。

1
2
3
4
5
6
7
8
9
10
11
$.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解决方案(没有Flash或任何其他浏览器插件)是隐藏的iframe技术,它允许模拟异步请求而不使用xmlhttpRequest对象。

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

如果做得正确,它实际上应该在任何浏览器上工作,但是它有一些警告,比如如何从IFRAME中获得响应。

在这种情况下,您可能更喜欢使用像Bifr这样的包装插件?ST使用IFRAME技术,但也提供了一个jQuery Ajax传输,允许用EDCOX1的3个这样的方法发送文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
$.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到不同的回退的整个堆栈,以及一些有用的特性来缓解这个过程。根据您的需求和需求,您可能需要考虑裸露的实现或这两个插件中的任何一个。


此Ajax文件上载jquery插件上载文件somehwere,并传递对回调的响应,没有其他内容。

  • 它不依赖于特定的HTML,只要给它一个
  • 它不需要您的服务器以任何特定的方式响应
  • 不管您使用多少文件,或者它们在页面上的位置

--少用如--

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

--或者--

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$('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');
  }
});


我一直在使用下面的脚本来上传图像,这正好可以正常工作。

HTML

1
<input id="file" type="file" name="file"/>

JavaScript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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);
});

解释

我使用response div来显示上传动画和上传完成后的响应。

最好的一点是,在使用此脚本时,您可以随文件发送额外的数据,如ID等。我在脚本中提到过extra-data

在PHP级别,这将作为正常的文件上传工作。额外的数据可以检索为$_POST数据。

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


你可以很容易地用普通的javascript来实现。以下是我当前项目的一个片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function(e) {
    var percent = (e.position/ e.totalSize);
    // Render a pretty progress bar
};
xhr.onreadystatechange = function(e) {
    if(this.readyState === 4) {
        // Handle file upload complete
    }
};
xhr.open('POST', '/upload', true);
xhr.setRequestHeader('X-FileName',file.name); // Pass the filename along
xhr.send(file);


只需jquery .ajax()即可上传。

HTML:

1
2
3
4
5
6
7
8
9
<form id="upload-form">
   
        <label for="file">File:</label>
        <input type="file" id="file" name="file" />
        <progress class="progress" value="0" max="100"></progress>
   
    <hr />
    <input type="submit" value="Submit" />
</form>

CSS

1
.progress { display: none; }

Javascript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
$(document).ready(function(ev) {
    $("#upload-form").on('submit', (function(ev) {
        ev.preventDefault();
        $.ajax({
            xhr: function() {
                var progress = $('.progress'),
                    xhr = $.ajaxSettings.xhr();

                progress.show();

                xhr.upload.onprogress = function(ev) {
                    if (ev.lengthComputable) {
                        var percentComplete = parseInt((ev.loaded / ev.total) * 100);
                        progress.val(percentComplete);
                        if (percentComplete === 100) {
                            progress.hide().val(0);
                        }
                    }
                };

                return xhr;
            },
            url: 'upload.php',
            type: 'POST',
            data: new FormData(this),
            contentType: false,
            cache: false,
            processData: false,
            success: function(data, status, xhr) {
                // ...
            },
            error: function(xhr, status, error) {
                // ...
            }
       });
    }));
});


我过去做这件事的最简单和最可靠的方法就是简单地用你的表单定位一个隐藏的iframe标签——然后它将在iframe中提交而不重新加载页面。

也就是说,如果你不想使用插件、javascript或任何其他形式的"魔法"而不是HTML。当然,你可以把它和javascript或者其他东西结合起来……

1
2
3
4
5
6
<form target="iframe" action="" method="post" enctype="multipart/form-data">
    <input name="file" type="file" />
    <input type="button" value="Upload" />
</form>

<iframe name="iframe" id="iframe" style="display:none"></iframe>

您还可以读取iframe onLoad的内容,查看服务器错误或成功响应,然后将其输出给用户。

chrome、iframes和onload

-注意-如果您对上传/下载时如何设置UI阻止程序感兴趣,只需继续阅读即可。

当前chrome在用于传输文件时不会触发iframe的onload事件。firefox、ie和edge都会触发文件传输的onload事件。

我找到的唯一适合Chrome的解决方案是使用cookie。

要在开始上传/下载时基本上做到这一点:

  • [客户端]开始一个间隔以查找是否存在cookie
  • [服务器端]使用文件数据执行所需的任何操作
  • [服务器端]为客户端间隔设置cookie
  • [客户端]interval看到cookie并像onload事件一样使用它。例如,你可以启动一个用户界面拦截器,然后上传(或者当你做了cookie时),你就删除了这个用户界面拦截器。

用饼干来做这个很难看,但它是有效的。

我做了一个jquery插件来处理chrome下载时的这个问题,你可以在这里找到

https://github.com/artisticphoenix/jquery-plugins/blob/master/idownloader.js网站

同样的基本原则也适用于上传。

使用下载程序(显然包括JS)

1
2
3
4
5
6
7
8
9
10
 $('body').iDownloader({
    "onComplete" : function(){
          $('#uiBlocker').css('display', 'none'); //hide ui blocker on complete
     }
 });

 $('somebuttion').click( function(){
      $('#uiBlocker').css('display', 'block'); //block the UI
      $('body').iDownloader('download', 'htttp://example.com/location/of/download');
 });

在服务器端,在传输文件数据之前,创建cookie

1
 setcookie('iDownloader', true, time() + 30,"/");

插件将看到cookie,然后触发onComplete回调。


我发现的解决方案是让

以隐藏的iframe为目标。然后,iframe可以运行js向用户显示它已经完成(页面加载时)。


我是在Rails环境中编写的。如果您使用轻量级的jquery表单插件,它只有大约五行javascript。

挑战在于让Ajax上传工作,因为标准的remote_form_for不理解多部分表单提交。它不会发送Rails用Ajax请求查找的文件数据。

这就是jquery表单插件发挥作用的地方。

这是它的Rails代码:

1
2
3
4
5
6
7
<% remote_form_for(:image_form,
                   :url => { :controller =>"blogs", :action => :create_asset },
                   :html => { :method => :post,
                              :id => 'uploadForm', :multipart => true })
                                                                        do |f| %>
 Upload a file: <%= f.file_field :uploaded_data %>
<% end %>

下面是相关的javascript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$('#uploadForm input').change(function(){
 $(this).parent().ajaxSubmit({
  beforeSubmit: function(a,f,o) {
   o.dataType = 'json';
  },
  complete: function(XMLHttpRequest, textStatus) {
   // XMLHttpRequest.responseText will contain the URL of the uploaded image.
   // Put it in an image element you create, or do with it what you will.
   // For example, if you have an image elemtn with id"my_image", then
   //  $('#my_image').attr('src', XMLHttpRequest.responseText);
   // Will set that image tag to display the uploaded image.
  },
 });
});

这是Rails控制器的动作,相当普通:

1
2
3
 @image = Image.new(params[:image_form])
 @image.save
 render :text => @image.public_filename

在过去的几周里,我一直在用它来写博客,它的工作方式就像一个冠军。


简单的Ajax上载程序是另一个选项:

https://github.com/lpology/simple-ajax-uploader

  • 跨浏览器——适用于IE7+、Firefox、Chrome、Safari、Opera
  • 支持多个并发上载——即使在非HTML5浏览器中也是如此
  • 没有Flash或外部CSS——只有一个5Kb的javascript文件
  • 可选,内置支持完全跨浏览器进度条(使用PHP的APC扩展)
  • 灵活和高度可定制——使用任何元素作为上传按钮,设计自己的进度指示器。
  • 不需要表单,只需提供一个元素作为上载按钮
  • 麻省理工学院许可证——免费用于商业项目

示例用法:

1
2
3
4
5
6
7
8
9
10
11
var uploader = new ss.SimpleUpload({
    button: $('#uploadBtn'), // upload button
    url: '/uploadhandler', // URL of server-side upload handler
    name: 'userfile', // parameter name of the uploaded file
    onSubmit: function() {
        this.setProgressBar( $('#progressBar') ); // designate elem as our progress bar
    },
    onComplete: function(file, response) {
        // do whatever after upload is finished
    }
});


jquery uploadify是另一个很好的插件,我以前用它上传文件。javascript代码简单如下:代码。但是,新版本在Internet Explorer中不起作用。

1
2
3
4
5
6
7
8
9
10
11
12
$('#file_upload').uploadify({
    'swf': '/public/js/uploadify.swf',
    'uploader': '/Upload.ashx?formGuid=' + $('#formGuid').val(),
    'cancelImg': '/public/images/uploadify-cancel.png',
    'multi': true,
    'onQueueComplete': function (queueData) {
        // ...
    },
    'onUploadStart': function (file) {
        // ...
    }
});

我做了很多搜索,并且我找到了另一个上传文件的解决方案,没有任何插件,只使用Ajax。解决方案如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$(document).ready(function () {
    $('#btn_Upload').live('click', AjaxFileUpload);
});

function AjaxFileUpload() {
    var fileInput = document.getElementById("#Uploader");
    var file = fileInput.files[0];
    var fd = new FormData();
    fd.append("files", file);
    var xhr = new XMLHttpRequest();
    xhr.open("POST", 'Uploader.ashx');
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
             alert('success');
        }
        else if (uploadResult == 'success')
            alert('error');
    };
    xhr.send(fd);
}


这里是另一个如何上传文件的解决方案(没有任何插件)

使用简单的javascripts和ajax(带有进度条)

HTML部分

1
2
3
4
5
6
7
8
<form id="upload_form" enctype="multipart/form-data" method="post">
    <input type="file" name="file1" id="file1">
    <input type="button" value="Upload File" onclick="uploadFile()">
    <progress id="progressBar" value="0" max="100" style="width:300px;"></progress>
    <h3 id="status">
    <p id="loaded_n_total">
</p>
</form>

JS部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function _(el){
    return document.getElementById(el);
}
function uploadFile(){
    var file = _("file1").files[0];
    // alert(file.name+" |"+file.size+" |"+file.type);
    var formdata = new FormData();
    formdata.append("file1", file);
    var ajax = new XMLHttpRequest();
    ajax.upload.addEventListener("progress", progressHandler, false);
    ajax.addEventListener("load", completeHandler, false);
    ajax.addEventListener("error", errorHandler, false);
    ajax.addEventListener("abort", abortHandler, false);
    ajax.open("POST","file_upload_parser.php");
    ajax.send(formdata);
}
function progressHandler(event){
    _("loaded_n_total").innerHTML ="Uploaded"+event.loaded+" bytes of"+event.total;
    var percent = (event.loaded / event.total) * 100;
    _("progressBar").value = Math.round(percent);
    _("status").innerHTML = Math.round(percent)+"% uploaded... please wait";
}
function completeHandler(event){
    _("status").innerHTML = event.target.responseText;
    _("progressBar").value = 0;
}
function errorHandler(event){
    _("status").innerHTML ="Upload Failed";
}
function abortHandler(event){
    _("status").innerHTML ="Upload Aborted";
}

PHP部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
$fileName = $_FILES["file1"]["name"]; // The file name
$fileTmpLoc = $_FILES["file1"]["tmp_name"]; // File in the PHP tmp folder
$fileType = $_FILES["file1"]["type"]; // The type of file it is
$fileSize = $_FILES["file1"]["size"]; // File size in bytes
$fileErrorMsg = $_FILES["file1"]["error"]; // 0 for false... and 1 for true
if (!$fileTmpLoc) { // if file not chosen
    echo"ERROR: Please browse for a file before clicking the upload button.";
    exit();
}
if(move_uploaded_file($fileTmpLoc,"test_uploads/$fileName")){ // assuming the directory name 'test_uploads'
    echo"$fileName upload is complete";
} else {
    echo"move_uploaded_file function failed";
}
?>

下面是示例应用程序


1
2
3
4
5
6
7
8
9
10
11
12
13
14
var formData=new FormData();
formData.append("fieldname","value");
formData.append("image",$('[name="filename"]')[0].files[0]);

$.ajax({
    url:"page.php",
    data:formData,
    type: 'POST',
    dataType:"JSON",
    cache: false,
    contentType: false,
    processData: false,
    success:function(data){ }
});

您可以使用表单数据发布所有值,包括图像。


要使用jquery异步上载文件,请使用以下步骤:

步骤1:在项目中打开nuget manager并添加包(jquery fileupload(只需将其写入搜索框中,它就会出现并安装它。)网址:https://github.com/blueimp/jquery-file-upload

步骤2:在HTML文件中添加以下脚本,这些脚本已通过运行上述包添加到项目中:

jquery.ui.widget.js

jquery.iframe-transport.js

jquery.fileupload.js

步骤3:按以下代码编写文件上传控制:

1
<input id="upload" name="upload" type="file" />

步骤4:将JS方法写为uploadFile,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 function uploadFile(element) {

            $(element).fileupload({

                dataType: 'json',
                url: '../DocumentUpload/upload',
                autoUpload: true,
                add: function (e, data) {          
                  // write code for implementing, while selecting a file.
                  // data represents the file data.
                  //below code triggers the action in mvc controller
                  data.formData =
                                    {
                                     files: data.files[0]
                                    };
                  data.submit();
                },
                done: function (e, data) {          
                   // after file uploaded
                },
                progress: function (e, data) {

                   // progress
                },
                fail: function (e, data) {

                   //fail operation
                },
                stop: function () {

                  code for cancel operation
                }
            });

        };

准备函数中的步骤5调用元素文件上传,启动过程如下:

1
2
3
4
5
$(document).ready(function()
{
    uploadFile($('#upload'));

});

第6步:编写MVC控制器,动作如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class DocumentUploadController : Controller
    {      

        [System.Web.Mvc.HttpPost]
        public JsonResult upload(ICollection<HttpPostedFileBase> files)
        {
            bool result = false;

            if (files != null || files.Count > 0)
            {
                try
                {
                    foreach (HttpPostedFileBase file in files)
                    {
                        if (file.ContentLength == 0)
                            throw new Exception("Zero length file!");                      
                        else
                            //code for saving a file

                    }
                }
                catch (Exception)
                {
                    result = false;
                }
            }


            return new JsonResult()
                {
                    Data=result
                };


        }

    }

使用html5的readasdataurl()或某些base64编码器将文件转换为base64。Fiddle在这里

1
2
3
4
5
6
7
8
var reader = new FileReader();

        reader.onload = function(readerEvt) {
            var binaryString = readerEvt.target.result;
            document.getElementById("base64textarea").value = btoa(binaryString);
        };

        reader.readAsBinaryString(file);

然后检索:

1
window.open("data:application/octet-stream;base64," + base64);

示例:如果您使用jquery,您可以轻松地上传文件。这是一个小而强的jquery插件,http://jquery.malsup.com/form/。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var $bar   = $('.ProgressBar');
$('.Form').ajaxForm({
  dataType: 'json',

  beforeSend: function(xhr) {
    var percentVal = '0%';
    $bar.width(percentVal);
  },

  uploadProgress: function(event, position, total, percentComplete) {
    var percentVal = percentComplete + '%';
    $bar.width(percentVal)
  },

  success: function(response) {
    // Response
  }
});

我希望它会有帮助


没有jquery的现代方法是,当用户选择一个文件时,使用从返回的filelist对象,然后使用fetch来发布包装在formdata对象周围的filelist。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// The input DOM element
const inputElement = document.querySelector('input');

// Listen for a file submit from user
inputElement.addEventListener('change', () => {
    const data = new FormData();
    data.append('file', inputElement.files[0]);
    data.append('imageName', 'flower');

    // Post to server
    fetch('/uploadImage', {
        method: 'POST',
        body: data
    });
});


您可以在这里看到一个解决方案和一个工作演示,它允许您预览表单文件并将其提交到服务器。对于您的案例,您需要使用Ajax来方便文件上传到服务器:

1
2
3
4
5
<from action="" id="formContent" method="post" enctype="multipart/form-data">
    <span>File</span>
    <input type="file" id="file" name="file" size="10"/>
    <input id="uploadbutton" type="button" value="Upload"/>
</form>

正在提交的数据是FormData。在jquery上,使用表单提交函数而不是按钮单击以提交表单文件,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$(document).ready(function () {
   $("#formContent").submit(function(e){

     e.preventDefault();
     var formdata = new FormData(this);

 $.ajax({
     url:"ajax_upload_image.php",
     type:"POST",
     data: formdata,
     mimeTypes:"multipart/form-data",
     contentType: false,
     cache: false,
     processData: false,
     success: function(){

     alert("successfully submitted");

     });
   });
});

查看更多详细信息


你可以使用

1
2
3
4
5
6
7
8
$(function() {
    $("#file_upload_1").uploadify({
        height        : 30,
        swf           : '/uploadify/uploadify.swf',
        uploader      : '/uploadify/uploadify.php',
        width         : 120
    });
});

演示


您可以通过使用XMLHutpRestQuess(不带Flash和iFrAMP依赖性)来进行异步上传,并将其他参数与文件名一起传递。用FrasDATA追加附加参数值并发送上载请求。

1
2
3
4
5
6
7
8
9
10
var formData = new FormData();
formData.append('parameter1', 'value1');
formData.append('parameter2', 'value2');
formData.append('file', $('input[type=file]')[0].files[0]);

$.ajax({
    url: 'post back url',
    data: formData,
// other attributes of AJAX
});

此外,SycFixJavaScript UI文件上传只使用事件参数为该方案提供了解决方案。您可以在这里找到文档,在此详细介绍这里的链接描述。


在这里异步查找文件的上载过程:https://developer.mozilla.org/en-us/docs/using_files_from_web_applications

链接中的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
if (isset($_FILES['myFile'])) {
    // Example:
    move_uploaded_file($_FILES['myFile']['tmp_name'],"uploads/" . $_FILES['myFile']['name']);
    exit;
}
?><!DOCTYPE html>
<html>
<head>
    dnd binary upload
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript">
        function sendFile(file) {
            var uri ="/index.php";
            var xhr = new XMLHttpRequest();
            var fd = new FormData();

            xhr.open("POST", uri, true);
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    // Handle response.
                    alert(xhr.responseText); // handle response.
                }
            };
            fd.append('myFile', file);
            // Initiate a multipart/form-data upload
            xhr.send(fd);
        }

        window.onload = function() {
            var dropzone = document.getElementById("dropzone");
            dropzone.ondragover = dropzone.ondragenter = function(event) {
                event.stopPropagation();
                event.preventDefault();
            }

            dropzone.ondrop = function(event) {
                event.stopPropagation();
                event.preventDefault();

                var filesArray = event.dataTransfer.files;
                for (var i=0; i<filesArray.length; i++) {
                    sendFile(filesArray[i]);
                }
            }
        }
   
</head>
<body>
   
        Drag & drop your file here...
   
</body>
</html>


使用html5和javascript,上传异步非常容易,我创建了上传逻辑和你的HTML,这不是完全工作,因为它需要API,但演示了它是如何工作的,如果你有一个端点称为/upload,从你的网站根目录,这个代码应该为你工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const asyncFileUpload = () => {
  const fileInput = document.getElementById("file");
  const file = fileInput.files[0];
  const uri ="/upload";
  const xhr = new XMLHttpRequest();
  xhr.upload.onprogress = e => {
    const percentage = e.loaded / e.total;
    console.log(percentage);
  };
  xhr.onreadystatechange = e => {
    if (xhr.readyState === 4 && xhr.status === 200) {
      console.log("file uploaded");
    }
  };
  xhr.open("POST", uri, true);
  xhr.setRequestHeader("X-FileName", file.name);
  xhr.send(file);
}
1
2
3
4
5
<form>
  <span>File</span>
  <input type="file" id="file" name="file" size="10" />
  <input onclick="asyncFileUpload()" id="upload" type="button" value="Upload" />
</form>

还有一些关于xmlhttpreques的进一步信息:

The XMLHttpRequest Object

All modern browsers support the XMLHttpRequest object.
The XMLHttpRequest object can be used to exchange data with a web
server behind the scenes. This means that it is possible to update
parts of a web page, without reloading the whole page.

Create an XMLHttpRequest Object

All modern browsers (Chrome, Firefox,
IE7+, Edge, Safari, Opera) have a built-in XMLHttpRequest object.

Syntax for creating an XMLHttpRequest object:

variable = new XMLHttpRequest();

Access Across Domains

For security reasons, modern browsers do not
allow access across domains.

This means that both the web page and the XML file it tries to load,
must be located on the same server.

The examples on W3Schools all open XML files located on the W3Schools
domain.

If you want to use the example above on one of your own web pages, the
XML files you load must be located on your own server.

有关详细信息,请继续阅读此处…


这是我的解决方案。

1
2
3
4
5
6
7
8
9
10
11
12
<form enctype="multipart/form-data">    

   
        <label class="control-label col-md-2" for="apta_Description">Description</label>
       
            <input class="form-control text-box single-line" id="apta_Description" name="apta_Description" type="text" value="">
       
   

    <input name="file" type="file" />
    <input type="button" value="Upload" />
</form>

和JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    $(':button').click(function () {
        var formData = new FormData($('form')[0]);
        $.ajax({
            url: '@Url.Action("Save","Home")',  
            type: 'POST',                
            success: completeHandler,
            data: formData,
            cache: false,
            contentType: false,
            processData: false
        });
    });    

    function completeHandler() {
        alert(":)");
    }

控制器

1
2
3
4
5
[HttpPost]
public ActionResult Save(string apta_Description, HttpPostedFileBase file)
{
    return Json(":)");
}


您可以通过javascript使用更新的fetch API。这样地:

1
2
3
4
5
6
7
8
9
10
function uploadButtonCLicked(){
    var input = document.querySelector('input[type="file"]')

    fetch('/url', {
      method: 'POST',
      body: input.files[0]
    }).then(res => res.json())   // you can do something with response
      .catch(error => console.error('Error:', error))
      .then(response => console.log('Success:', response));
}

优点:Fetch API是所有现代浏览器的本机支持,因此您不必导入任何内容。另外,请注意fetch()返回一个承诺,然后使用.then(..code to handle response..)异步处理该承诺。


您可以使用javascript或jquery进行异步多文件上载,而不使用任何插件。您还可以在进度控制中显示文件上载的实时进度。我遇到了两个很好的链接-

  • 基于ASP.NET Web窗体的多个文件上载功能,带有进度条
  • jquery中基于ASP.NET MVC的多文件上载
  • 服务器端语言是C语言,但是您可以对其进行一些修改,使其与其他语言(如PHP)一起工作。

    文件上载ASP.NET核心MVC:

    在视图中,以HTML格式创建文件上载控件:

    1
    2
    3
    4
    <form method="post" asp-action="Add" enctype="multipart/form-data">
        <input type="file" multiple name="mediaUpload" />
        <button type="submit">Submit</button>
    </form>

    现在在控制器中创建操作方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [HttpPost]
    public async Task<IActionResult> Add(IFormFile[] mediaUpload)
    {
        //looping through all the files
        foreach (IFormFile file in mediaUpload)
        {
            //saving the files
            string path = Path.Combine(hostingEnvironment.WebRootPath,"some-folder-path");
            using (var stream = new FileStream(path, FileMode.Create))
            {
                await file.CopyToAsync(stream);
            }
        }
    }

    hostingEnvironment变量是IHostingEnvironment类型,可以使用依赖项注入将其注入控制器,例如:

    1
    2
    3
    4
    5
    private IHostingEnvironment hostingEnvironment;
    public MediaController(IHostingEnvironment environment)
    {
        hostingEnvironment = environment;
    }


    你也可以考虑使用https://uppy.io之类的工具。

    它可以在不离开页面的情况下进行文件上载,并提供一些奖励,如拖放、在浏览器崩溃/网络不稳定时恢复上载以及从Instagram导入。它是开源的,不依赖jquery/react/angular/vue,但可以与之一起使用。免责声明:作为它的创造者,我有偏见;)


    这是一个古老的问题,但仍然没有正确答案,因此:

    你试过jquery文件上传吗?

    下面是上面链接中的一个示例,可以解决您的问题:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $('#fileupload').fileupload({
        add: function (e, data) {
            var that = this;
            $.getJSON('/example/url', function (result) {
                data.formData = result; // e.g. {id: 123}
                $.blueimp.fileupload.prototype
                    .options.add.call(that, e, data);
            });
        }
    });

    对于PHP,请查看https://developer.hyvor.com/php/image-upload-ajax-php-mysql

    HTML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <html>
    <head>
        Image Upload with AJAX, PHP and MYSQL
    </head>
    <body>
    <form onsubmit="submitForm(event);">
        <input type="file" name="image" id="image-selecter" accept="image/*">
        <input type="submit" name="submit" value="Upload Image">
    </form>
    Uploading...
    <img id="preview">
    </body>
    </html>

    JavaScript

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    var previewImage = document.getElementById("preview"),  
        uploadingText = document.getElementById("uploading-text");

    function submitForm(event) {
        // prevent default form submission
        event.preventDefault();
        uploadImage();
    }

    function uploadImage() {
        var imageSelecter = document.getElementById("image-selecter"),
            file = imageSelecter.files[0];
        if (!file)
            return alert("Please select a file");
        // clear the previous image
        previewImage.removeAttribute("src");
        // show uploading text
        uploadingText.style.display ="block";
        // create form data and append the file
        var formData = new FormData();
        formData.append("image", file);
        // do the ajax part
        var ajax = new XMLHttpRequest();
        ajax.onreadystatechange = function() {
            if (this.readyState === 4 && this.status === 200) {
                var json = JSON.parse(this.responseText);
                if (!json || json.status !== true)
                    return uploadError(json.error);

                showImage(json.url);
            }
        }
        ajax.open("POST","upload.php", true);
        ajax.send(formData); // send the form data
    }

    PHP

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    <?php
    $host = 'localhost';
    $user = 'user';
    $password = 'password';
    $database = 'database';
    $mysqli = new mysqli($host, $user, $password, $database);


     try {
        if (empty($_FILES['image'])) {
            throw new Exception('Image file is missing');
        }
        $image = $_FILES['image'];
        // check INI error
        if ($image['error'] !== 0) {
            if ($image['error'] === 1)
                throw new Exception('Max upload size exceeded');

            throw new Exception('Image uploading error: INI Error');
        }
        // check if the file exists
        if (!file_exists($image['tmp_name']))
            throw new Exception('Image file is missing in the server');
        $maxFileSize = 2 * 10e6; // in bytes
        if ($image['size'] > $maxFileSize)
            throw new Exception('Max size limit exceeded');
        // check if uploaded file is an image
        $imageData = getimagesize($image['tmp_name']);
        if (!$imageData)
            throw new Exception('Invalid image');
        $mimeType = $imageData['mime'];
        // validate mime type
        $allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif'];
        if (!in_array($mimeType, $allowedMimeTypes))
            throw new Exception('Only JPEG, PNG and GIFs are allowed');

        // nice! it's a valid image
        // get file extension (ex: jpg, png) not (.jpg)
        $fileExtention = strtolower(pathinfo($image['name'] ,PATHINFO_EXTENSION));
        // create random name for your image
        $fileName = round(microtime(true)) . mt_rand() . '.' . $fileExtention; // anyfilename.jpg
        // Create the path starting from DOCUMENT ROOT of your website
        $path = '/examples/image-upload/images/' . $fileName;
        // file path in the computer - where to save it
        $destination = $_SERVER['DOCUMENT_ROOT'] . $path;

        if (!move_uploaded_file($image['tmp_name'], $destination))
            throw new Exception('Error in moving the uploaded file');

        // create the url
        $protocol = stripos($_SERVER['SERVER_PROTOCOL'],'https') === true ? 'https://' : 'http://';
        $domain = $protocol . $_SERVER['SERVER_NAME'];
        $url = $domain . $path;
        $stmt = $mysqli -> prepare('INSERT INTO image_uploads (url) VALUES (?)');
        if (
            $stmt &&
            $stmt -> bind_param('s', $url) &&
            $stmt -> execute()
        ) {
            exit(
                json_encode(
                    array(
                        'status' => true,
                        'url' => $url
                    )
                )
            );
        } else
            throw new Exception('Error in saving into the database');

    } catch (Exception $e) {
        exit(json_encode(
            array (
                'status' => false,
                'error' => $e -> getMessage()
            )
        ));
    }

    您可以使用以下代码。

    1
    async: false(true)