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

XMLHttpRequest Level 2 标准(仍然是一个工作草案)定义了接口。此接口允许将对象追加到 XHR 请求(Ajax 请求)。FormDataFile

顺便说一句,这是一个新功能 - 在过去,使用了“hidden-iframe-trick”(在我的另一个问题中阅读)。

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

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

其中 是一个字段,并且是 Ajax 请求的成功处理程序。input<input type="file">handler

这在所有浏览器中都运行良好(同样,除了IE)。

现在,我想让这个功能与jQuery一起工作。我试过这个:

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

$.post( 'http://example.com/script.php', fd, handler );

不幸的是,这不起作用(抛出“非法调用”错误 - 屏幕截图在这里)。我假设jQuery需要一个简单的键值对象来表示表单 - 字段名称/值,并且我传入的实例显然是不兼容的。FormData

现在,由于可以将实例传递到 ,我希望也可以使其与jQuery一起使用。FormDataxhr.send()


更新:

我在jQuery的Bug Tracker上创建了一个“功能工单”。它就在这里:http://bugs.jquery.com/ticket/9995

有人建议我使用“Ajax预过滤器”...


更新:

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

网页:

<form>
    <input type="file" id="file" name="file">
    <input type="submit">
</form>

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

上面的代码导致这个HTTP请求:

multipartformdata

这就是我需要的 - 我想要“多部分/表单数据”内容类型!


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

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

但是,这会导致:

wrongcontenttype

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


答案 1

我相信你可以这样做:

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

笔记:

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

  • 将 to 设置为命令式,因为否则 jQuery 将错误地设置它contentTypefalse


答案 2

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

基于普拉迪克的例子:

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

在某些情况下,当强制jQuery ajax做意想不到的事情时,事件是一个很好的地方。有一段时间,人们一直在使用mimeType来覆盖mimeType,然后在1.5.1中被添加到jQuery中。您应该能够在之前发送事件中修改 jqXHR 对象上的任何内容。beforeSendbeforeSend