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
截至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解决方案。他们可以灵活地处理自己的职位…
为此,我建议使用优秀的上载程序插件。您的
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功能),则可以使用
您也可以发送不带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'); } }); |
我一直在使用下面的脚本来上传图像,这正好可以正常工作。
HTML1 | <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
最好的一点是,在使用此脚本时,您可以随文件发送额外的数据,如ID等。我在脚本中提到过
在PHP级别,这将作为正常的文件上传工作。额外的数据可以检索为
这里你没有使用插件和其他东西。您可以根据需要更改代码。你不是盲目地在这里编码。这是任何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
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
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,然后触发
我发现的解决方案是让