使用jquery.ajax发送多部分/formdata

x7rlezfr  于 2021-06-17  发布在  Mysql
关注(0)|答案(13)|浏览(419)

我在使用jquery的ajax函数向服务器端php脚本发送文件时遇到问题。你可以用 $('#fileinput').attr('files') 但是怎么可能把这些数据发送到服务器呢?生成的数组( $_POST )在服务器端,php脚本是0( NULL )使用文件输入时。
我知道这是可能的(尽管我直到现在还没有找到任何jquery解决方案,只有prototye代码)(http://webreflection.blogspot.com/2009/03/safari-4-multiple-upload-with-progress.html)).
这似乎是相对较新的,所以请不要提文件上传将不可能通过xhr/ajax,因为它肯定是工作。
我需要在Safari5,ff和chrome的功能将很好,但不是必不可少的。
我现在的代码是:

$.ajax({
    url: 'php/upload.php',
    data: $('#file').attr('files'),
    cache: false,
    contentType: 'multipart/form-data',
    processData: false,
    type: 'POST',
    success: function(data){
        alert(data);
    }
});
smdnsysy

smdnsysy1#

如果表单是在html中定义的,那么将表单传递到构造函数比迭代和添加图像更容易。

$('#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){
            ...
mccptt67

mccptt672#

我只是想给拉斐尔的回答再添一点。下面是如何让php产生相同的 $_FILES ,无论是否使用javascript提交。
html表单:

<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>

php产生了这个 $_FILES ,在不使用javascript提交时:

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提交文件。。。

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的特点 $_FILES 在使用该javascript提交后,数组如下所示:

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
        )

)

这是一个很好的数组,事实上有些人改变了 $_FILES 但是我发现用同样的方法工作是很有用的 $_FILES ,不管是否使用javascript提交。因此,以下是js的一些小改动:

// 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()的构造函数中删除了form元素——它在safari中修复了此代码。)
这个代码有两个作用。
检索 input name属性,使html更易于维护。现在,只要 form 如果这个班有图片,其他一切都会自动处理。也就是说 input 不需要任何特别的名字。
普通html提交的数组格式由data.append行中的javascript重新创建。注意括号。
有了这些变化,用javascript提交现在产生了完全相同的结果 $_FILES 数组作为简单的html提交。

f45qwnt8

f45qwnt83#

现在您甚至不需要jquery:)fetchapi支持表

let result = fetch('url', {method: 'POST', body: new FormData(document.querySelector("#form"))})
r8xiu3jd

r8xiu3jd4#

旧版本的ie不支持formdata(formdata的完整浏览器支持列表如下:https://developer.mozilla.org/en-us/docs/web/api/formdata).
您可以使用jquery插件(例如,http://malsup.com/jquery/form/#code-示例)或者,您可以使用基于iframe的解决方案通过ajax发布多部分表单数据:https://developer.mozilla.org/en-us/docs/learn/html/forms/sending_forms_through_javascript

xienkqul

xienkqul5#

我只是根据我读到的一些信息建立了这个函数。
使用它就像使用 .serialize() ,而不是 .serializefiles(); .
在这里做我的测试。

//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);
zzlelutf

zzlelutf6#

formdata类确实可以工作,但是在ios safari中(至少在iphone上),我无法按原样使用raphael schweikert的解决方案。
mozilla dev提供了一个很好的关于操作formdata对象的页面。
因此,在页面的某个位置添加一个空表单,指定enctype:

<form enctype="multipart/form-data" method="post" name="fileinfo" id="fileinfo"></form>

然后,将formdata对象创建为:

var data = new FormData($("#fileinfo"));

按照拉斐尔的密码进行。

jtw3ybtb

jtw3ybtb7#

devin venable的答案接近于我想要的,但是我想要一个可以在多个表单上工作的,并且使用表单中已经指定的操作,这样每个文件都可以放在正确的位置。
我还想使用jquery的on()方法,这样就可以避免使用.ready()。
这让我想到:(用jquery选择器替换formselector)

$(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.
    });

});
mccptt67

mccptt678#

如果文件输入 name 表示数组和标志 multiple ,然后解析整个 formFormData ,不需要迭代 append() 输入文件。 FormData 将自动处理多个文件。

$('#submit_1').on('click', function() {
  let data = new FormData($("#my_form")[0]);

  $.ajax({
    url: '/path/to/php_file',
    type: 'POST',
    data: data,
    processData: false,
    contentType: false,
    success: function(r) {
      console.log('success', r);
    },
    error: function(r) {
      console.log('error', r);
    }
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="my_form">
  <input type="file" name="multi_img_file[]" id="multi_img_file" accept=".gif,.jpg,.jpeg,.png,.svg" multiple="multiple" />
  <button type="button" name="submit_1" id="submit_1">Not type='submit'</button>
</form>

请注意 button type="button" 是用的,不是 type="submit" . 这表明不依赖于使用 submit 获取此功能。
结果 $_FILES chrome开发工具中的条目如下:

multi_img_file:
  error: (2) [0, 0]
  name: (2) ["pic1.jpg", "pic2.jpg"]
  size: (2) [1978036, 2446180]
  tmp_name: (2) ["/tmp/phphnrdPz", "/tmp/phpBrGSZN"]
  type: (2) ["image/jpeg", "image/jpeg"]

注意:有些情况下,一些图像作为单个文件上载时可以正常上载,但在一组多个文件中上载时会失败。症状是php报告为空 $_POST 以及 $_FILES 没有ajax抛出任何错误。Chrome75.0.3770.100和PHP7.0出现问题。在我的测试集中,似乎只有几十张图片中的一张会出现这种情况。

izkcnapc

izkcnapc9#

通过jquery获取窗体对象->$(“#id”)[0]
data=new formdata($(“#id”)[0]);
好的,数据是你想要的

ztmd8pv5

ztmd8pv510#

上面所有的解决方案看起来都很好,但是formdata()对象不需要任何参数,而是在示例化它之后使用append(),就像上面写的那样:
formdata.append(val.name,val.value);

7fyelxc5

7fyelxc511#

我今天遇到的一个问题值得指出:如果ajax调用的url被重定向,那么content type的头“multipart/formdata”可能会丢失。
例如,我在http://server.com/context?param=x
在chrome的network标签中,我看到了这个请求的正确的multipart头,但是随后302重定向到了http://server.com/context/?param=x (注意上下文后面的斜杠)
在重定向过程中,多部分头丢失。如果这些解决方案不适合您,请确保请求不会被重定向。

x6492ojm

x6492ojm12#

从Safari5/Firefox4开始,使用 FormData 班级:

var data = new FormData();
jQuery.each(jQuery('#file')[0].files, function(i, file) {
    data.append('file-'+i, file);
});

所以现在你有一个 FormData 对象,准备与xmlhttprequest一起发送。

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);
    }
});

你必须设定 contentType 选择 false ,强制jquery不添加 Content-Type 头,否则,边界字符串将从中丢失。另外,你必须离开 processData 标志设置为false,否则,jquery将尝试转换 FormData 变成一根绳子,就会失败。
现在可以使用以下方法在php中检索文件:

$_FILES['file-0']

(只有一个文件, file-0 ,除非您指定 multiple 属性,在这种情况下,数字将随着每个文件的增加而增加。)
对旧浏览器使用formdata仿真

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对象,而不是手动迭代文件:

var data = new FormData(jQuery('form')[0]);

使用php本机数组而不是计数器
只需将文件元素命名为相同的名称,并在括号中结束名称:

jQuery.each(jQuery('#file')[0].files, function(i, file) {
    data.append('file[]', file);
});
``` `$_FILES['file']` 然后将是一个数组,其中包含每个上载文件的文件上载字段。实际上,我建议在我的初始解决方案中使用这个方法,因为它更容易迭代。
hwazgwia

hwazgwia13#

看看我的代码,它为我做的工作

$( '#formId' )
  .submit( function( e ) {
    $.ajax( {
      url: 'FormSubmitUrl',
      type: 'POST',
      data: new FormData( this ),
      processData: false,
      contentType: false
    } );
    e.preventDefault();
  } );

相关问题