如何在jQuery中使用Ajax请求发送FormData对象?

Šim*_*das 468 javascript ajax jquery html5 multipartform-data

XMLHttpRequest的2级标准(还是工作草案)定义FormData的接口.此接口允许将File对象附加到XHR请求(Ajax请求).

顺便说一句,这是一个新功能 - 在过去,使用了"隐藏iframe技巧"(在我的另一个问题中阅读).

这就是它的工作原理(例子):

var xhr = new XMLHttpRequest(),
    fd = new FormData();

fd.append( 'file', input.files[0] );
xhr.open( 'POST', 'http://example.com/script.php', true );
xhr.onreadystatechange = handler;
xhr.send( fd );
Run Code Online (Sandbox Code Playgroud)

where input是一个<input type="file">字段,handler是Ajax请求的成功处理程序.

这在所有浏览器中都很漂亮(除了IE之外).

现在,我想使这个功能与jQuery一起使用.我试过这个:

var fd = new FormData();    
fd.append( 'file', input.files[0] );

$.post( 'http://example.com/script.php', fd, handler );
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不起作用(抛出"非法调用"错误 - 截图在这里).我假设jQuery需要一个表示form-field-names/values的简单键值对象,而FormData我传入的实例显然是不兼容的.

现在,由于可以将FormData实例传入xhr.send(),我希望它也可以使它与jQuery一起使用.


更新:

我在jQuery的Bug Tracker上创建了一个"功能票".它在这里:http://bugs.jquery.com/ticket/9995

我被建议使用"Ajax prefilter"......


更新:

首先,让我演示一个演示我想要实现的行为的演示.

HTML:

<form>
    <input type="file" id="file" name="file">
    <input type="submit">
</form>
Run Code Online (Sandbox Code Playgroud)

JavaScript的:

$( 'form' ).submit(function ( e ) {
    var data, xhr;

    data = new FormData();
    data.append( 'file', $( '#file' )[0].files[0] );

    xhr = new XMLHttpRequest();

    xhr.open( 'POST', 'http://hacheck.tel.fer.hr/xml.pl', true );
    xhr.onreadystatechange = function ( response ) {};
    xhr.send( data );

    e.preventDefault();
});
Run Code Online (Sandbox Code Playgroud)

以上代码导致此HTTP请求:

multipartformdata

这就是我需要的 - 我想要"multipart/form-data"内容类型!


建议的解决方案是这样的:

$( 'form' ).submit(function ( e ) {
    var data;

    data = new FormData();
    data.append( 'file', $( '#file' )[0].files[0] );

    $.ajax({
        url: 'http://hacheck.tel.fer.hr/xml.pl',
        data: data,
        processData: false,
        type: 'POST',
        success: function ( data ) {
            alert( data );
        }
    });

    e.preventDefault();
});
Run Code Online (Sandbox Code Playgroud)

但是,这导致:

wrongcontenttype

如您所见,内容类型错误...

pra*_*eek 834

我相信你可以这样做:

var fd = new FormData();    
fd.append( 'file', input.files[0] );

$.ajax({
  url: 'http://example.com/script.php',
  data: fd,
  processData: false,
  contentType: false,
  type: 'POST',
  success: function(data){
    alert(data);
  }
});
Run Code Online (Sandbox Code Playgroud)

设置processData为false可以防止jQuery自动将数据转换为查询字符串.有关详细信息,请参阅文档.

设置contentType为false是必要的,否则jQuery 将错误地设置它.

  • 是的,我相信您可以通过在$ .ajax参数中添加键值对来手动将contentType设置为'multipart/form-data'. (9认同)
  • 在 Firefox 和 Chrome 中测试。这就是解决方案。 (2认同)
  • 将 processData 和 contentType 设置为 false 为我解决了这个问题。谢谢,那是不愉快的。 (2认同)

Ben*_*yne 28

有一些尚未提及的技术可供您使用.首先在ajax params中设置contentType属性.

以pradeek为例:

$('form').submit(function (e) {
    var data;

    data = new FormData();
    data.append('file', $('#file')[0].files[0]);

    $.ajax({
        url: 'http://hacheck.tel.fer.hr/xml.pl',
        data: data,
        processData: false,
        type: 'POST',

        // This will override the content type header, 
        // regardless of whether content is actually sent.
        // Defaults to 'application/x-www-form-urlencoded'
        contentType: 'multipart/form-data', 

        //Before 1.5.1 you had to do this:
        beforeSend: function (x) {
            if (x && x.overrideMimeType) {
                x.overrideMimeType("multipart/form-data");
            }
        },
        // Now you should be able to do this:
        mimeType: 'multipart/form-data',    //Property added in 1.5.1

        success: function (data) {
            alert(data);
        }
    });

    e.preventDefault();
});
Run Code Online (Sandbox Code Playgroud)

在某些情况下,当强制jQuery ajax执行非预期的事情时,beforeSend事件是一个很好的地方.有一段时间人们使用beforeSend覆盖mimeType之前将其添加到1.5.1中的jQuery中.您应该能够在before send事件中修改jqXHR对象上的任何内容.

  • 这有一个问题:[规范](http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html)要求多部分内容类型包含边界参数(具体来说,它表示为*必需*参数). (4认同)

Luc*_*cky 19

您可以使用以下代码在ajax请求中发送FormData对象,

$("form#formElement").submit(function(){
    var formData = new FormData($(this)[0]);
});
Run Code Online (Sandbox Code Playgroud)

这与接受的答案非常相似,但是问题主题的实际答案.这将自动在FormData中提交表单元素,您无需手动将数据附加到FormData变量.

ajax方法看起来像这样,

$("form#formElement").submit(function(){
    var formData = new FormData($(this)[0]);
    //append some non-form data also
    formData.append('other_data',$("#someInputData").val());
    $.ajax({
        type: "POST",
        url: postDataUrl,
        data: formData,
        processData: false,
        contentType: false,
        dataType: "json",
        success: function(data, textStatus, jqXHR) {
           //process data
        },
        error: function(data, textStatus, jqXHR) {
           //process error msg
        },
});
Run Code Online (Sandbox Code Playgroud)

您也可以手动将FormData对象中的表单元素作为参数传递给它

var formElem = $("#formId");
var formdata = new FormData(form[0]);
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你.;)

  • 不是`$(this)[0]`和`this`相同? (9认同)
  • @halbano` $(this)`返回不是数组,但是jQuery集合对象可以像数组一样迭代.`form [0]`与`form.first()`几乎完全相同,它只返回第一个真正的HTML元素. (2认同)

dmn*_*hhn 5

您可以使用$ .ajax beforeSend事件来操纵标头.

...

beforeSend: function(xhr) { 
    xhr.setRequestHeader('Content-Type', 'multipart/form-data');
}
Run Code Online (Sandbox Code Playgroud)

...

有关其他信息,请参阅此链接:http://msdn.microsoft.com/en-us/library/ms536752(v = vs.85).aspx


Rah*_*dav 5

JavaScript:

function submitForm() {
    var data1 = new FormData($('input[name^="file"]'));
    $.each($('input[name^="file"]')[0].files, function(i, file) {
        data1.append(i, file);
    });

    $.ajax({
        url: "<?php echo base_url() ?>employee/dashboard2/test2",
        type: "POST",
        data: data1,
        enctype: 'multipart/form-data',
        processData: false, // tell jQuery not to process the data
        contentType: false // tell jQuery not to set contentType
    }).done(function(data) {
        console.log("PHP Output:");
        console.log(data);
    });
    return false;
}
Run Code Online (Sandbox Code Playgroud)

PHP:

public function upload_file() {
    foreach($_FILES as $key) {
        $name = time().$key['name'];
        $path = 'upload/'.$name;
        @move_uploaded_file($key['tmp_name'], $path);
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我这样做,这对我有用,我希望这会有所帮助:)

   <div id="data">
        <form>
            <input type="file" name="userfile" id="userfile" size="20" />
            <br /><br />
            <input type="button" id="upload" value="upload" />
        </form>
    </div>
  <script>
        $(document).ready(function(){
                $('#upload').click(function(){

                    console.log('upload button clicked!')
                    var fd = new FormData();    
                    fd.append( 'userfile', $('#userfile')[0].files[0]);

                    $.ajax({
                      url: 'upload/do_upload',
                      data: fd,
                      processData: false,
                      contentType: false,
                      type: 'POST',
                      success: function(data){
                        console.log('upload success!')
                        $('#data').empty();
                        $('#data').append(data);

                      }
                    });
                });
        });
    </script>   
Run Code Online (Sandbox Code Playgroud)