Sending multipart/formdata with jQuery.ajax
使用jquery的ajax函数向服务器端的php脚本发送文件时遇到问题。可以使用
我知道这是可能的(尽管我到目前为止还没有找到任何jquery解决方案,但只有原型代码(http://webreflection.blogspot.com/2009/03/safari-4-multiple-upload-with-progress.html))。
这似乎是相对较新的,所以请不要提及通过XHR/AJAX上传文件是不可能的,因为它确实有效。
我需要Safari 5的功能,FF和Chrome很好,但不是必需的。
我现在的代码是:
1 2 3 4 5 6 7 8 9 10 11 | $.ajax({ url: 'php/upload.php', data: $('#file').attr('files'), cache: false, contentType: 'multipart/form-data', processData: false, type: 'POST', success: function(data){ alert(data); } }); |
从Safari 5/firefox 4开始,最容易使用
1 2 3 4 | var data = new FormData(); jQuery.each(jQuery('#file')[0].files, function(i, file) { data.append('file-'+i, file); }); |
所以现在您有了一个
1 2 3 4 5 6 7 8 9 10 11 12 | jQuery.ajax({ url: 'php/upload.php', data: data, cache: false, contentType: false, processData: false, method: 'POST', type: 'POST', // For jQuery < 1.9 success: function(data){ alert(data); } }); |
必须将
现在可以使用以下方法在PHP中检索文件:
1 | $_FILES['file-0'] |
(只有一个文件,
对旧浏览器使用FormData仿真
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | var opts = { url: 'php/upload.php', data: data, cache: false, contentType: false, processData: false, method: 'POST', type: 'POST', // For jQuery < 1.9 success: function(data){ alert(data); } }; if(data.fake) { // Make sure no text encoding stuff is done by xhr opts.xhr = function() { var xhr = jQuery.ajaxSettings.xhr(); xhr.send = xhr.sendAsBinary; return xhr; } opts.contentType ="multipart/form-data; boundary="+data.boundary; opts.data = data.toString(); } jQuery.ajax(opts); |
从现有表单创建FormData
也可以使用现有表单对象的内容创建FormData对象,而不是手动迭代文件:
1 | var data = new FormData(jQuery('form')[0]); |
使用PHP本机数组而不是计数器
只需将文件元素命名为相同,并在括号内结束名称:
1 2 3 | jQuery.each(jQuery('#file')[0].files, function(i, file) { data.append('file[]', file); }); |
EDOCX1×9将是一个包含文件上传字段的数组,用于上传的每个文件。事实上,我在最初的解决方案中推荐了这一点,因为迭代过程比较简单。
只是想给拉斐尔的一个伟大的答案加一点。下面是如何让PHP产生相同的EDCOX1×10,而不管您是否使用JavaScript提交。
HTML表单:
1 2 3 4 5 | <form enctype="multipart/form-data" action="/test.php" method="post" class="putImages"> <input name="media[]" type="file" multiple/> <input class="button" type="submit" alt="Upload" value="Upload" /> </form> |
当不使用javascript提交时,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 | Array ( [media] => Array ( [name] => Array ( [0] => Galata_Tower.jpg [1] => 518f.jpg ) [type] => Array ( [0] => image/jpeg [1] => image/jpeg ) [tmp_name] => Array ( [0] => /tmp/phpIQaOYo [1] => /tmp/phpJQaOYo ) [error] => Array ( [0] => 0 [1] => 0 ) [size] => Array ( [0] => 258004 [1] => 127884 ) ) ) |
如果您进行渐进式增强,使用Raphael的JS提交文件…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var data = new FormData($('input[name^="media"]')); jQuery.each($('input[name^="media"]')[0].files, function(i, file) { data.append(i, file); }); $.ajax({ type: ppiFormMethod, data: data, url: ppiFormActionURL, cache: false, contentType: false, processData: false, success: function(data){ alert(data); } }); |
…这就是PHP的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | Array ( [0] => Array ( [name] => Galata_Tower.jpg [type] => image/jpeg [tmp_name] => /tmp/phpAQaOYo [error] => 0 [size] => 258004 ) [1] => Array ( [name] => 518f.jpg [type] => image/jpeg [tmp_name] => /tmp/phpBQaOYo [error] => 0 [size] => 127884 ) ) |
这是一个很好的数组,实际上有些人把
1 2 3 4 5 6 7 8 9 10 | // match anything not a [ or ] regexp = /^[^[\]]+/; var fileInput = $('.putImages input[type="file"]'); var fileInputName = regexp.exec( fileInput.attr('name') ); // make files available var data = new FormData(); jQuery.each($(fileInput)[0].files, function(i, file) { data.append(fileInputName+'['+i+']', file); }); |
(2017年4月14日编辑:我从formdata()的构造函数中删除了表单元素——这在Safari中修复了此代码。)
这个代码有两个作用。
通过这些更改,用javascript提交现在可以生成与用简单HTML提交完全相同的
我只是根据我读到的一些信息构建了这个函数。
使用它就像使用
在我的测试中工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //USAGE: $("#form").serializefiles(); (function($) { $.fn.serializefiles = function() { var obj = $(this); /* ADD FILE TO PARAM AJAX */ var formData = new FormData(); $.each($(obj).find("input[type='file']"), function(i, tag) { $.each($(tag)[0].files, function(i, file) { formData.append(tag.name, file); }); }); var params = $(obj).serializeArray(); $.each(params, function (i, val) { formData.append(val.name, val.value); }); return formData; }; })(jQuery); |
看看我的代码,它为我完成了任务
1 2 3 4 5 6 7 8 9 10 11 | $( '#formId' ) .submit( function( e ) { $.ajax( { url: 'FormSubmitUrl', type: 'POST', data: new FormData( this ), processData: false, contentType: false } ); e.preventDefault(); } ); |
如果表单是在HTML中定义的,那么将表单传递到构造函数比迭代和添加图像更容易。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $('#my-form').submit( function(e) { e.preventDefault(); var data = new FormData(this); // <-- 'this' is your form element $.ajax({ url: '/my_URL/', data: data, cache: false, contentType: false, processData: false, type: 'POST', success: function(data){ ... |
Devin Venable的回答接近我想要的,但我想要一个可以处理多个表单的答案,并使用表单中已经指定的操作,以便每个文件都可以放到正确的位置。
我还想使用jquery的on()方法,这样可以避免使用.ready()。
这让我明白了:(用jQuery选择器替换FultS选择器)
1 2 3 4 5 6 7 8 9 10 11 12 13 | $(document).on('submit', formSelecter, function( e ) { e.preventDefault(); $.ajax( { url: $(this).attr('action'), type: 'POST', data: new FormData( this ), processData: false, contentType: false }).done(function( data ) { //do stuff with the data you got back. }); }); |
formdata类确实有效,但是在iOS Safari(至少在iPhone上)中,我不能像现在一样使用Raphael Schweikert的解决方案。
Mozilla Dev有一个关于操作FormData对象的好页面。
因此,在页面的某个位置添加一个空表单,指定enctype:
1 | <form enctype="multipart/form-data" method="post" name="fileinfo" id="fileinfo"></form> |
然后,将FormData对象创建为:
1 | var data = new FormData($("#fileinfo")); |
按照拉斐尔的法典进行。
nova days您甚至不需要jquery:)获取api支持表
1 | let result = fetch('url', {method: 'POST', body: new FormData(documemt.querySelector("#form"))}) |
上面所有的解决方案看起来都很好和优雅,但是formData()对象不需要任何参数,而是在实例化之后使用append(),就像上面写的那样:
formdata.append(val.name,val.value);
旧版本的IE不支持FormData(完整的FormData浏览器支持列表如下:https://developer.mozilla.org/en-us/docs/web/api/formdata)。
您可以使用jquery插件(例如,http://malsup.com/jquery/form/代码示例),也可以使用基于iframe的解决方案通过ajax发布多部分表单数据:https://developer.mozilla.org/en-us/docs/learn/html/forms/sending_forms_through_javascript
我今天遇到的一个问题是值得指出的,与这个问题相关的:如果Ajax调用的URL被重定向,那么内容类型"multipart/form data"的头可能会丢失。
例如,我在发布到http://server.com/context?PARAM= X
在chrome的"网络"选项卡中,我看到了此请求的正确多部分头,但随后302重定向到http://server.com/context/?param=x(注意上下文后面的斜线)
重定向期间,多部分头丢失。如果这些解决方案对您不起作用,请确保不会重定向请求。