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

Posted

技术标签:

【中文标题】如何在 jQuery 中使用 Ajax 请求发送 FormData 对象? [复制]【英文标题】:How to send FormData objects with Ajax-requests in jQuery? [duplicate] 【发布时间】:2011-10-21 22:14:56 【问题描述】:

XMLHttpRequest Level 2 标准(仍是工作草案)定义了FormData 接口。此接口允许将 File 对象附加到 XHR 请求(Ajax 请求)。

顺便说一句,这是一项新功能 - 过去曾使用过“hidden-iframe-trick”(请参阅​​ my other question 了解相关内容)。

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

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

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

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

现在,既然可以将FormData 实例传递给xhr.send(),我希望它也可以与jQuery 一起使用。


更新:

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

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


更新:

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

html

<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 请求:

这就是我需要的 - 我想要“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();
);

但是,这会导致:

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

【问题讨论】:

是的!这是一个好主意!也感谢您提供的信息。我最近发现了一个可以做到这一点的 sn-p,但它不是 jQuery,我想知道 jQuery 是否可以做到。这对我来说更像是一个答案而不是一个问题。随时通知我们! 现在如果我/我们知道在所说的预过滤器中放什么。 这里的情况相同。任何人的更多线索? @zaf Setting processData:false 是朝着正确方向迈出的一步(请参阅 pradeek 提出的解决方案)。现在,如果我可以手动设置“Content-Type”HTTP 请求标头...有关详细信息,请参阅我更新的问题。 这里没有回答您的问题吗? ***.com/questions/5392344/… 【参考方案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);
  
);

注意事项:

processData 设置为false 可以防止jQuery 自动将数据转换为查询字符串。请参阅the docs 了解更多信息。

contentType 设置为false 是必要的,否则jQuery will set it incorrectly。

【讨论】:

不幸的是,这会导致设置了错误的“Content-Type”HTTP 请求标头。请参阅我的问题以详细说明我想要实现的目标以及您当前的解决方案为何不令人满意。也许我可以手动设置 Content-Type? 是的,我相信您可以通过在 $.ajax 参数中添加键值对来手动将 contentType 设置为“multipart/form-data”。 嗨@pradeek,我们在这里尝试了这个解决方案(***.com/questions/10215425/…),但不清楚如何在POST 请求的正文中传递图像数据。有什么线索吗?谢谢! 在 Firefox 和 Chrome 中测试。这就是解决方案。 将 processData 和 contentType 设置为 false 为我解决了这个问题。谢谢,那很不愉快。【参考方案2】:

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

beforeSend: function(xhr)  
    xhr.setRequestHeader('Content-Type', 'multipart/form-data');

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

【讨论】:

【参考方案3】:

有一些尚未提及的技术可供您使用。首先在 ajax 参数中设置 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();
);

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

【讨论】:

这有一个问题:the spec 要求多部分内容类型包含边界参数(具体来说,它被声明为 必需 参数)。 @romkyns 我是从头顶开始编码的。如果您有一些我没有的经验/知识,请继续编辑答案!既然您提到了它,快速搜索就会出现:***.com/questions/5933949/… 这应该会让您朝着正确的方向前进。 (如果您愿意,可以从该示例中获取并将其合并到上面的 jQuery 中。) 实际上,当前接受的答案(我对其进行了编辑以添加关键修复)终于做了正确的事情。这很棘手:) 我对这个解决方案寄予厚望,但我的 $_FILES 仍然是 NULL...【参考方案4】:

如果您想使用 ajax 提交文件,请使用“jquery.form.js” 这样可以轻松提交所有表单元素。

样品 http://jquery.malsup.com/form/#ajaxSubmit

粗略的看法:

<form id='AddPhotoForm' method='post' action='../photo/admin_save_photo.php' enctype='multipart/form-data'>

<script type="text/javascript">
function showResponseAfterAddPhoto(responseText, statusText)
 
    information= responseText;
    callAjaxtolist();
    $("#AddPhotoForm").resetForm();
    $("#photo_msg").html('<div class="album_msg">Photo uploaded Successfully...</div>');        
;

$(document).ready(function()
    $('.add_new_photo_div').live('click',function()
            var options = success:showResponseAfterAddPhoto;  
            $("#AddPhotoForm").ajaxSubmit(options);
        );
);
</script>

【讨论】:

【参考方案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;

PHP:

public function upload_file() 
    foreach($_FILES as $key) 
        $name = time().$key['name'];
        $path = 'upload/'.$name;
        @move_uploaded_file($key['tmp_name'], $path);
    

【讨论】:

【参考方案6】:

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

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

【讨论】:

这与接受的答案有何不同? fd.append('userfile', $('#userfile')[0].files[0]);这是您需要添加 id 才能使输入文件正常工作的不同之处。 这个比别人帮了我..【参考方案7】:

而不是 - fd.append( 'userfile', $('#userfile')[0].files[0]);

使用 - fd.append( 'file', $('#userfile')[0].files[0]);

【讨论】:

如果你能解释一下区别,我给你一个cookie。【参考方案8】:

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

$("form#formElement").submit(function()
    var formData = new FormData($(this)[0]);
);

这与接受的答案非常相似,但却是问题主题的实际答案。这将在 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
        ,
);

您也可以像这样手动将 FormData 对象内的表单元素作为参数传递

var formElem = $("#formId");
var formdata = new FormData(formElem[0]);

希望对您有所帮助。 ;)

【讨论】:

$(this)[0]this不一样吗? 为什么 $(this) 返回一个数组? @halbano $(this) 返回的不是数组,而是可以像数组一样迭代的 jQuery 集合对象。 form[0]form.first() 几乎完全相同,后者只是返回第一个真正的 HTML 元素。

以上是关于如何在 jQuery 中使用 Ajax 请求发送 FormData 对象? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

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

如何在 jQuery 中发送带有 Ajax 请求的 FormData 对象? [复制]

如何在 jQuery ajax 中使用 GET 请求发送原始数据?

如何在 jQuery $.ajax() 发布请求中向 MVC 控制器方法发送模型

如何使用 jQuery 在不同的端口上发送 AJAX 请求?

如何使用 jQuery $.ajax 将请求参数数组发送到 servlet?