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

그래도 @lanzz? 직렬화 된 것은 데이터에만 작동하는 것으로 보이지만 다른 하나는 파일에서만 작동하는 것으로 보입니까?
— Dan

이 MDN 페이지 에서 판단 할 때 모든 양식 데이터는 사용할 때 제출해야합니다.FormData
— lanzz

1
@lanzz 당신이 맞아요, 그것은 내가 잘못된 양식 ID를 사용하고 있어야한다고 생각한 방식으로 작동합니다. 아약스로 하나의 양식을 통해 파일과 데이터를 모두 업로드 할 수 있습니다.
— Dan

다중 선택 파일 입력이있을 때는 작동하지 않는 것 같습니다. 첫 번째 파일 만 업로드합니다.
— Sami Al-Subhi

답변:


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 + 아약스

$("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가 IE 8 또는 9에없는 HTML5 개체이므로이 솔루션이 작동하지 않습니다.
— Xavier Guzman

34
$(this)[0]의 별칭 this일 뿐이 므로 new FormData(this)충분해야합니다.
— r3wt

9
FormData Object를 검사하는 것은 불가능합니다. 이 질문을 참조하십시오 (Object가 항상 비어 있기 때문에 방금 수행 한 것과 같은 단서가없는 사람은).
— Laura

28
향후 독자 : contentType 및 processData 선언이 중요합니다. 자세한 내용은 이 답변 을 참조하십시오.
— AaronSieb

5
는 async: false작업이 필요한 모바일 (단일 스레드) 브라우저에서 차단됩니다 보이지 않는
— 제레미 Daalder

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는 아니지만 동일한 질문을 가진 사람들에게 여전히 유용 할 수 있습니다.
— Roey

3
나는 왜이 답변이 -2를 얻는 지 믿을 수 없다. 나는 레거시 브라우저 지원이 필요할 때 이것을 사용했다.
— Sijav

다른 답변은 '이전 브라우저는 작동하지 않습니다'또는 'iframe 해킹을 사용할 수 있습니다'라고 언급하지만이를 해결하지 않으므로이 답변은 스레드에 있어야합니다. 멋진 코드 조각, onload를 올바르게 사용하는 방법 +1
— mschr

18

ASP.Net MVC에서 HttpPostedFilebase를 사용하여 동일한 문제가 발생했으며 제출시 양식을 사용하는 대신 클릭해야 할 부분을 클릭해야했습니다.

$(".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로 IE에서 입력 제어를

<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

고마워 친구! 많은 시간을 절약했습니다.
— 액세스가 거부 됨

장고와 잘 어울립니다.
— csandreas1

고마워 친구! 아래 2 줄이 나를 위해 일했습니다. var form = $ ( "# Form"); var formData = 새 FormData (form [0]);
— Rajiv Kumar

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 속성에 이미 설정되어 있지만 어떤 이유로 든 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>

위에서 언급 한 다른 사람 contentType과 processData필드 에도 특별한주의를 기울이십시오 .


1
"나에게는 Ajax 요청의 'multipart / form-data'필드가 enctype없이 작동하지 않았습니다." — 효과가 없었습니다. jQuery.ajax에 의해 인식되는 속성이 아닙니다. 참조 문서enctype 전혀 언급되지 않습니다.
— Quentin

앞에서 언급했듯이 여러 가지 다른 답변을 시도했지만 작동하지 않았습니다. JS 콘솔에 인코딩 오류를 나타내는 Ajax 오류가 표시되었습니다. 나중에이 튜토리얼 을 따라 마침내 코드를 작동시키고 여기에 게시했습니다. 아마도 enctype이유 때문에 문서에 필드가 포함되어 있지 않을 수도 있습니다. jQuery 소스 코드를 확인하지 않았으므로 확실하게 말할 수 없습니다.
— Adithya Upadhya 19

"아마도, enctype 필드는 이유로 문서에서 다루지 않았습니다." — jQuery는 아무 것도하지 않기 때문에 말도 안되기 때문입니다.
— Quentin

아마도 당신은 Mkyong 에게 연락 하여 그와 대화를 나눌 수 있습니다. enctype필드 를 제거하여 코드를 다시 테스트 했지만 더 이상 파일을 업로드하지 않습니다 (인코딩 유형 오류 리턴). jQuery 소스 코드를 확인하지 않았으므로 어떻게 작동하는지 잘 모르겠습니다. 나는 비슷한 문제에 갇힌 다른 사람들을 돕기 위해이 답변을 게시했습니다. 난 여기에 upvotes를 위해 낚시하지 않습니다 ... 당신은 더 질문 / 의견이 있으면 의견 대신 채팅을하자.
— Adithya Upadhya 19

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 Method에서 매개 변수를 HttpPostedFileBase UploadFile로 전달하고 파일 입력이 Action Method의 매개 변수에서 언급 한 것과 동일한 지 확인하십시오. AJAX Begin 양식에서도 작동합니다.

위에서 언급 한 코드에 포스트 콜을 정의하고 요구 사항에 따라 코드에서 메소드를 참조 할 수 있으므로 AJAX BEGIN 양식은 여기에서 작동하지 않습니다.

나는 늦게 응답한다는 것을 알고 있지만 이것이 나를 위해 일한 것입니다.


1

간단하지만보다 효과적인 방법
new FormData()은 컨테이너 (또는 가방)와 같습니다. 모든 속성이나 파일을 넣을 수 있습니다. 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 개의 파일 또는 데이터를 추가 할 수 있습니다.

그리고 Node.js에서 Script.js 파일에서 Route 파일로 AJAX 요청을하는 경우
req.body데이터 (예 : 텍스트)
req.files에 액세스하여 파일 (예 : 이미지, 비디오 등) 에 액세스하는 데 주의하십시오.


-1

필자의 경우 헤더를 통해 전송 된 정보와 FormData 객체를 사용하여 전송 된 파일이있는 POST 요청을해야했습니다.

여기에 몇 가지 답변을 조합하여 작동하게 만들었으므로 기본적으로 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);
?>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.