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>

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


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.