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


384

我正在为表单使用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>

2
FormData方法应适用于包含所需内容的表单,而不仅仅是文件上载字段。虽然它不受广泛支持。
lanzz 2012年

@lanzz哪个呢?带有序列化的一个似乎仅适用于数据,而另一个似乎仅适用于文件?
2012年

根据此MDN页面的判断,使用时应提交所有表单数据FormData
lanzz 2012年

1
@lanzz,您是对的,它以我认为使用错误的表单ID的方式起作用,您可以使用ajax通过一种表单上传文件和数据。
2012年

当有多选文件输入时,这似乎不起作用。它仅上传第一个文件。
Sami Al-Subhi

Answers:


458

我遇到的问题是使用了错误的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);
    });
});

17
在IE中<10该溶液的版本将不会工作,因为FORMDATA是一种HTML5对象,而不是存在于IE 8或9
泽维尔Guzman的

34
$(this)[0]只是的别名this,因此new FormData(this)应该足够。
r3wt 2014年

9
似乎无法检查FormData对象,请参见此问题(对于任何因为我一直都是空的对象而陷入与我一样的笨拙的人)。
劳拉

28
对于将来的读者:contentType和processData声明很重要。有关更多信息,请参见此答案
AaronSieb

5
async: false似乎并不需要为这个工作而导致阻塞移动(单线程)浏览器
杰里米·达尔德

33

另一种选择是使用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”下


1
的确,它不是Ajax,对于有相同问题的人仍然有用。
罗伊

3
我简直不敢相信为什么这个答案得到-2,我最终使用了这个,因为我需要旧版浏览器支持
Sijav 2016年

该答案应在主题中,因为其他答案指出“旧版浏览器无法正常工作”或“可以使用iframe hack”,但从未解决过。一段不错的代码,还显示了如何正确使用onload +1
mschr

18

我在带有HttpPostedFilebase的ASP.Net MVC中遇到了同样的问题,而不是在Submit上使用表单,我需要在需要做一些事情的地方单击按钮,然后,如果一切正常,那么提交表单就可以了,这就是我的工作方式

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

1
您节省了时间。:)
Suhail Mumtaz Awan

就我而言,我必须使用:contentType : "application/octet-stream"
Christophe Roussy 18/09/19

谢谢哥们儿!您节省了很多时间。
拒绝访问

它与Django兼容,很好!
csandreas1

谢了哥们!以下两行对我有用。var form = $(“#Form”); var formData = new FormData(form [0]);
拉吉夫·库马尔

15

或更短:

$("form#data").submit(function() {
    var formData = new FormData(this);
    $.post($(this).attr("action"), formData, function() {
        // success    
    });
    return false;
});

因此,您如何使用相同的脚本验证数据字段,即表单中是否有文本字段和文件字段
George

6

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

即使enctype 已经在form属性中设置了,由于某种原因,如果enctype没有显式声明(jQuery 3.3.1),Ajax请求也不会自动识别。

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

如上文所述,也请特别注意contentTypeand processData字段。


1
“对我来说,没有enctype,它就无法工作:Ajax请求中的'multipart / form-data'字段。” —不会有任何效果。它不是jQuery.ajax识别的属性。请参阅文档,其中enctype完全没有提及。
Quentin

就像我之前提到的那样,我尝试了多种不同的答案,但是它们都无法正常工作。JS控制台中显示了一个Ajax错误,指出了编码错误。后来,我遵循了本教程该教程最终使我的代码生效,并将其发布在这里。也许,enctype字段由于某种原因未包含在文档中。我没有检查jQuery源代码,所以我不能确定地说。
Adithya Upadhya,

“也许由于某种原因,文档中未包含enctype字段。” —这是因为jQuery不执行任何操作,所以这是胡说八道。
昆汀

也许您可以联系Mkyong并与他交谈。我通过删除该enctype字段再次测试了我的代码,该字段不再上传文件(返回编码类型错误)。我不确定该如何工作,因为我没有检查jQuery源代码。我发布此答案的目的是帮助陷入类似问题的其他人。我不是在这里争取投票...如果您还有其他问题/意见,让我们聊天而不是发表评论。
Adithya Upadhya,

1

对我来说,下面的代码工作

$(function () {
    debugger;
    document.getElementById("FormId").addEventListener("submit", function (e) {
        debugger;
        if (ValidDateFrom()) { // Check Validation 
            var form = e.target;
            if (form.getAttribute("enctype") === "multipart/form-data") {
                debugger;
                if (form.dataset.ajax) {
                    e.preventDefault();
                    e.stopImmediatePropagation();
                    var xhr = new XMLHttpRequest();
                    xhr.open(form.method, form.action);
                    xhr.onreadystatechange = function (result) {
                        debugger;
                        if (xhr.readyState == 4 && xhr.status == 200) {
                            debugger;
                            var responseData = JSON.parse(xhr.responseText);
                            SuccessMethod(responseData); // Redirect to your Success method 
                        }
                    };
                    xhr.send(new FormData(form));
                }
            }
        }
    }, true);
});

在您的Action Post方法中,将参数作为HttpPostedFileBase UploadFile传递,并确保您的文件输入与Action Method参数中提到的相同。它也应该与AJAX Begin表单一起使用。

在此记住,由于您在上述代码中定义了post调用,因此您的AJAX BEGIN表单将无法在此处使用,并且您可以根据要求在代码中引用您的方法

我知道我回答晚了,但这对我有用


0

一种简单但更有效的方法:
new FormData()本身就像一个容器(或袋子)。您可以将所有内容放入attr或文件中。您唯一需要附加的attribute, file, fileName示例是:

let formData = new FormData()
formData.append('input', input.files[0], input.files[0].name)

并在AJAX请求中传递它。例如:

    let formData = new FormData()
    var d = $('#fileid')[0].files[0]

    formData.append('fileid', d);
    formData.append('inputname', value);

    $.ajax({
        url: '/yourroute',
        method: 'POST',
        contentType: false,
        processData: false,
        data: formData,
        success: function(res){
            console.log('successfully')
        },
        error: function(){
            console.log('error')
        }
    })

您可以使用FormData附加n个文件或数据。

并且如果您要从Script.js文件向Node.js中的Route文件发出AJAX请求,请当心不要使用
req.body访问数据(即文本)
req.files来访问文件(即图像,视频等)


-1

在我的情况下,我必须发出POST请求,该请求具有通过标头发送的信息,以及使用FormData对象发送的文件。

我通过结合使用此处的一些答案来使其工作,因此基本上可以工作的是在我的Ajax请求中包含以下五行:

 contentType: "application/octet-stream",
 enctype: 'multipart/form-data',
 contentType: false,
 processData: false,
 data: formData,

其中formData是这样创建的变量:

 var file = document.getElementById('uploadedFile').files[0];
 var form = $('form')[0];
 var formData = new FormData(form);
 formData.append("File", file);

1
contentType: "application/octet-stream",确实有害,并且不会造成问题的唯一原因是因为您稍后将其覆盖了两行。
Quentin

1
enctype: 'multipart/form-data',是没有意义的。jQuery.ajax无法识别该参数。
Quentin

…其余答案将无法覆盖问题标题中“数据文件” 的“数据”位。
Quentin

-2
<form id="form" method="post" action="otherpage.php" 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 type='button' id='submit_btn'>Submit</button>
</form>

<script>
$(document).on("click", "#submit_btn", function (e) {
    //Prevent Instant Click  
    e.preventDefault();
    // Create an FormData object 
    var formData = $("#form").submit(function (e) {
        return;
    });
    //formData[0] contain form data only 
    // You can directly make object via using form id but it require all ajax operation inside $("form").submit(<!-- Ajax Here   -->)
    var formData = new FormData(formData[0]);
    $.ajax({
        url: $('#form').attr('action'),
        type: 'POST',
        data: formData,
        success: function (response) {
            console.log(response);
        },
        contentType: false,
        processData: false,
        cache: false
    });
    return false;
});
</script>

///// otherpage.php

<?php
    print_r($_FILES);
?>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.