使用 Ajax 以一种形式同时上传数据和文件?

IT技术 javascript jquery ajax forms
2021-02-01 00:02:25

我在表单中使用 jQuery 和 Ajax 来提交数据和文件,但我不确定如何以一种形式同时发送数据和文件?

我目前对这两种方法做的几乎相同,但是将数据收集到数组中的方式不同,数据使用.serialize();但文件使用= new FormData($(this)[0]);

是否可以结合这两种方法来通过 Ajax 以一种形式上传文件和数据?

数据 jQuery、Ajax 和 html

$("form#data").submit(function(){

    var formData = $(this).serialize();

    $.ajax({
        url: window.location.pathname,
        type: 'POST',
        data: formData,
        async: false,
        success: function (data) {
            alert(data)
        },
        cache: false,
        contentType: false,
        processData: false
    });

    return false;
});

<form id="data" method="post">
    <input type="text" name="first" value="Bob" />
    <input type="text" name="middle" value="James" />
    <input type="text" name="last" value="Smith" />
    <button>Submit</button>
</form>

文件 jQuery、Ajax 和 html

$("form#files").submit(function(){

    var formData = new FormData($(this)[0]);

    $.ajax({
        url: window.location.pathname,
        type: 'POST',
        data: formData,
        async: false,
        success: function (data) {
            alert(data)
        },
        cache: false,
        contentType: false,
        processData: false
    });

    return false;
});

<form id="files" method="post" enctype="multipart/form-data">
    <input name="image" type="file" />
    <button>Submit</button>
</form>

如何将上述内容结合起来,以便我可以通过 Ajax 以一种形式发送数据和文件?

我的目标是能够使用 Ajax 在一个帖子中发送所有这些表单,这可能吗?

<form id="datafiles" method="post" enctype="multipart/form-data">
    <input type="text" name="first" value="Bob" />
    <input type="text" name="middle" value="James" />
    <input type="text" name="last" value="Smith" />
    <input name="image" type="file" />
    <button>Submit</button>
</form>
6个回答

我遇到的问题是使用了错误的 jQuery 标识符。

可以使用 ajax以一种形式上传数据和文件

PHP + HTML

<?php

print_r($_POST);
print_r($_FILES);
?>

<form id="data" method="post" enctype="multipart/form-data">
    <input type="text" name="first" value="Bob" />
    <input type="text" name="middle" value="James" />
    <input type="text" name="last" value="Smith" />
    <input name="image" type="file" />
    <button>Submit</button>
</form>

jQuery + Ajax

$("form#data").submit(function(e) {
    e.preventDefault();    
    var formData = new FormData(this);

    $.ajax({
        url: window.location.pathname,
        type: 'POST',
        data: formData,
        success: function (data) {
            alert(data)
        },
        cache: false,
        contentType: false,
        processData: false
    });
});

精简版

$("form#data").submit(function(e) {
    e.preventDefault();
    var formData = new FormData(this);    

    $.post($(this).attr("action"), formData, function(data) {
        alert(data);
    });
});
在 IE < 10 的版本中,此解决方案不起作用,因为 FormData 是一个 HTML5 对象,在 IE 8 或 9 中不存在。
2021-03-16 00:02:25
$(this)[0]只是 的别名this,所以new FormData(this)应该足够了。
2021-03-17 00:02:25
对于未来的读者: contentType 和 processData 声明很重要。有关更多信息,请参阅此答案
2021-03-25 00:02:25
async: false似乎不需要它工作并导致移动(单线程)浏览器阻塞
2021-03-25 00:02:25
似乎不可能检查 FormData 对象,请参阅这个问题(对于任何遇到与我刚才一样的无知的人,因为对象总是空的)。
2021-04-04 00:02:25

另一种选择是使用 iframe 并将表单的目标设置为它。

你可以试试这个(它使用 jQuery):

function ajax_form($form, on_complete)
{
    var iframe;

    if (!$form.attr('target'))
    {
        //create a unique iframe for the form
        iframe = $("<iframe></iframe>").attr('name', 'ajax_form_' + Math.floor(Math.random() * 999999)).hide().appendTo($('body'));
        $form.attr('target', iframe.attr('name'));
    }

    if (on_complete)
    {
        iframe = iframe || $('iframe[name="' + $form.attr('target') + '"]');
        iframe.load(function ()
        {
            //get the server response
            var response = iframe.contents().find('body').text();
            on_complete(response);
        });
    }
}

它适用于所有浏览器,您不需要序列化或准备数据。不利的一面是您无法监控进度。

此外,至少对于 chrome,该请求不会出现在开发人员工具的“xhr”选项卡中,而是出现在“doc”下

这个答案应该在线程中,因为其他答案指出“旧浏览器不起作用”或“可以使用 iframe hack”,但从未解决它们。不错的一段代码,还展示了如何正确使用 onload +1
2021-03-10 00:02:25
我简直不敢相信为什么这个答案会得到 -2,我最终使用了它,因为我需要旧版浏览器支持
2021-03-12 00:02:25
确实它不是 Ajax,仍然可以对有相同问题的人有用。
2021-04-04 00:02:25

我在带有 HttpPostedFilebase 的 ASP.Net MVC 中遇到了同样的问题,而不是在提交时使用表单,我需要使用单击按钮,在那里我需要做一些事情,然后如果一切正常,提交表单,这就是我如何让它工作的

$(".submitbtn").on("click", function(e) {

    var form = $("#Form");

    // you can't pass Jquery form it has to be javascript form object
    var formData = new FormData(form[0]);

    //if you only need to upload files then 
    //Grab the File upload control and append each file manually to FormData
    //var files = form.find("#fileupload")[0].files;

    //$.each(files, function() {
    //  var file = $(this);
    //  formData.append(file[0].name, file[0]);
    //});

    if ($(form).valid()) {
        $.ajax({
            type: "POST",
            url: $(form).prop("action"),
            //dataType: 'json', //not sure but works for me without this
            data: formData,
            contentType: false, //this is requireded please see answers above
            processData: false, //this is requireded please see answers above
            //cache: false, //not sure but works for me without this
            error   : ErrorHandler,
            success : successHandler
        });
    }
});

这将比正确填充您的 MVC 模型,请确保在您的模型中,HttpPostedFileBase[] 的属性与html 中的输入控件名称具有相同的名称,即

<input id="fileupload" type="file" name="UploadedFiles" multiple>

public class MyViewModel
{
    public HttpPostedFileBase[] UploadedFiles { get; set; }
}
就我而言,我不得不使用: contentType : "application/octet-stream"
2021-03-26 00:02:25
谢了哥们!以下两行对我有用。var form = $("#Form"); var formData = new FormData(form[0]);
2021-04-02 00:02:25
你是一个节省时间的人。:)
2021-04-08 00:02:25
谢谢哥们儿!你节省了很多时间。
2021-04-09 00:02:25

或更短:

$("form#data").submit(function() {
    var formData = new FormData(this);
    $.post($(this).attr("action"), formData, function() {
        // success    
    });
    return false;
});
那么有了这个,您如何使用相同的脚本验证数据字段,也就是说,如果您的表单中有一个文本字段和一个文件字段
2021-03-10 00:02:25

对我来说,它enctype: 'multipart/form-data'在 Ajax 请求中没有字段就不起作用我希望它可以帮助陷入类似问题的人。

尽管enctype 已经在表单属性中设置了,但出于某种原因,Ajax 请求并没有自动识别enctype没有显式声明的(jQuery 3.3.1)。

// Tested, this works for me (jQuery 3.3.1)

fileUploadForm.submit(function (e) {   
    e.preventDefault();
    $.ajax({
            type: 'POST',
            url: $(this).attr('action'),
            enctype: 'multipart/form-data',
            data: new FormData(this),
            processData: false,
            contentType: false,
            success: function (data) {
                console.log('Thank God it worked!');
            }
        }
    );
});

// enctype field was set in the form but Ajax request didn't set it by default.

<form action="process/file-upload" enctype="multipart/form-data" method="post" >

     <input type="file" name="input-file" accept="text/plain" required> 
     ...
</form>

正如上面提到的其他人,还请特别注意contentTypeprocessData字段。

也许你可以联系Mkyong并与他交谈。我通过删除该enctype字段再次测试了我的代码,它不再上传文件(编码类型错误返回)。我不确定它是如何工作的,因为我没有检查过 jQuery 源代码。我发布此答案的目的是帮助陷入类似问题的其他人。我不是在这里寻求投票...如果您有进一步的问题/意见,让我们聊天而不是评论。
2021-03-16 00:02:25
“对我来说,如果 Ajax 请求中没有 enctype: 'multipart/form-data' 字段,它就无法工作。” ——那不会有任何影响。它不是 jQuery.ajax 识别的属性。请参阅文档,其中enctype完全没有提及。
2021-03-19 00:02:25
就像我之前提到的,我尝试了多种不同的答案,但都没有奏效。JS 控制台中显示了一个 Ajax 错误,说明编码错误。后来我跟着这个教程终于让我的代码工作了,我把它贴在这里。也许,enctype出于某种原因,文档中未涵盖该字段。我还没有检查 jQuery 源代码,所以我不能肯定地说。
2021-03-28 00:02:25
“也许,文档中没有包含 enctype 字段是有原因的。” — 那是因为 jQuery 没有用它做任何事情,所以它是无稽之谈。
2021-03-31 00:02:25