본문 바로가기
프로그래밍/server

formData 객체란?

by 한코코 2022. 11. 16.

formData란

<form>
    <input type="text" name="name" value="이름입력" />
    <input type="password" name="password" value="비밀번호 입력" />
    <input type="submit" value="완료" />
</form>

HTML5의 form태그를 사용해서 input값을 서버에 전송했지만, 자바스크립트에서 FormData() 클래스를 사용해 똑같이 스크립트로 전송할 수 있다. 즉, HTML이 아닌 자바스크립트 단에서 폼 데이터를 쉽게 다루도록 도와주는 객체다.

HTML에서 submit 제출동작은 Ajax를 통해 서버에게 제출한다.

 

하지만 HTML이 아니라 자바스크립트 단에서 form 전송동작이 필요한 경우가 있다.

이미지 같은 멀티미디어 파일을 페이지 전환없이 폼 데이터를 비동기로 제출하고 싶을때

자바스크립트로 좀더 타이트하게 폼 데이터를 관리하고 싶을때

이럴때 formData 객체를 이용한다고 보면 된다.

 

네트워크 메서드가 formData 객체를 body로 받는것이 formData의 특징이며, 이때 브라우저가 보내는 HTTP메시지는 인코딩되고 Content-Type 속성은 mulipart/form-data로 지정된 후 전송된다.

서버 관점에선 FormData를 사용한 방식과 일반 폼 전송 방식에 차이는 없다.

// 자바스크립트로 작성하는 form 태그
let formData = new FormData([form]); // FormData 객체 생성자
formData.append('item','hi'); // <input name="item" value="hi"> 와 같다.

폼 객체에 append() 메소드로 key, value 값을 차례로 추가해주면 input 태그에 값을 넣는것과 같이 사용할 수 있다.

값은 무조건 '문자열'로 자동변환된다. 객체나 배열같은 복잡한 문자열은 사용할 수 없다.

 

 

 

 

 

formData 사용법

  • formData.append(name, value) – name과 value를 가진 폼 필드를 추가
    formData.append(name, blob, fileName) – <input type="file">형태의 필드를 추가. 세 번째 인수 fileName은 (필드 이름이 아니고) 사용자가 해당 이름을 가진 파일을 폼에 추가한 것처럼 설정해줌
  • formData.delete(name) – name에 해당하는 필드를 삭제. null 값이 들어감
  • formData.has(name) – name에 해당하는 필드가 있으면 true를, 그렇지 않으면 false를 반환

 

폼은 name이 같은 필드 여러개를 허용하기 때문에 append 메서드를 여러번 호출해 이름이 같은 필드를 추가해도 문제가 없다.

  • formData.get(name) – name에 해당하는 필드의 value를 가져옴
  • formData.getAll(name) - 주어진 name에 해당하는 필드의 모든 value를 배열형태로 반환

 

set과 append 메서드가 다른점은, set은 name과 동일한 이름을 가진 필드를 모두 제거하고 새로운 필드 하나를 추가한다는 점이다. 즉, set메서드를 사용하면 name을 가진 필드가 단 한개만 존재하도록 만들 수 있다. 이외엔 append와 기능이 같다.

  • formData.set(name, value)
  • formData.set(name, blob, fileName)

 

 

 

 

 

 

간단한 폼 전송하기

formData는 자바스크립트 클래스기 때문에 서버에 전송하려면 fetch api를 사용해야 한다. ( fetch면 axios도 사용할 수 있겠다.)

주의해야할 점은 body 속성을 json이나 객체 타입이 아닌 formdata 타입 형식에 맞춰서 보내야한다.

var formData = new FormData();
formData.append('key1', 'value1');
formData.append('key2', 'value2');
 
fetch('https://httpbin.org/post', {
    method: 'POST',
    cache: 'no-cache',
    body: formData // body 부분에 폼데이터 변수를 할당
})
.then((response) => response.json())
.then((data) => {
    console.log(data);
});

일일히 append하여 폼 데이터값을 구성하는게 번거롭다면 URLSearchParams()를 사용해보자.

일반 객체형태를 formdata형식으로 자동변환 해주기 때문에 가독성 좋게 전송할 수 있다.

fetch('https://httpbin.org/post', {
    method: 'POST',
    cache: 'no-cache',
    body: new URLSearchParams({ // 일반 객체를 fordata형식으로 변환해주는 클래스
        aaa: 'a1',
        bbb: 'b1'
    })
})
.then((response) => response.json())
.then((data) => {
    console.log(data);
});

 

 

 

 

 

 

formData에 이미지 담아 보내기

이미지와 같은 멀티미디어 파일을 폼 데이터에 담고싶다면 formData 객체를 생성하고, 이미지 파일이 담긴 input 태그를 querySelector로 받아와서 files[0]을 append로 더해주면 된다.

<body>
    <input type="file" id="fileInput">
    <button type="submit" id="sendButton">전송</button>
 
    <script>
        const fileInput = document.querySelector("#fileInput");
        const sendButton = document.querySelector("#sendButton");
 
        sendButton.addEventListener("click",function(){
 
            let formData = new FormData();
            // form Data 객체 생성
            formData.append("attachedImage", fileInput.files[0]);
            // 파일 인풋에 들어간 파일들은 files 라는 리스트로 저장된다.
            // input에 multiple을 선언해 여러개의 파일을 선택한 경우가 아니라면 files[0] 으로 input에 추가한 파일 객체를 찾을 수 있다.
            
        });
    </script>
</body>

 

이미지 같이 동적으로 생성된 바이너리(2진법) 파일은 Blob 객체를 통해 전송할 수 있다.

이미지를 별도로 넘겨주는 것보다 폼에 필드를 추가하고 여기에 이미지의 메타데이터를 담아 넘겨주는 것이 편리하다. 서버도 원시 바이너리 데이터를 받는것보다 multipart-encoded 폼을 받는게 더 적합하다.

Blob란?
SQL 데이터베이스에서 유래하였으며 '대형 이진 객체(Binary Large Object)를 의미하며, 일련의 데이터를 처리하거나 간접 참조하는 객체다. 대개 바이트의 크기를 알아내거나 해당 MIME(Multipurpose Internet Mail Extensions, 파일변환) 타입이 무엇인지 요청하며, 데이터를 작은 Blob으로 나누는 등의 작업에 사용된다. 데이터 자체라기보다는 데이터를 간접적으로 접근하기 위한 객체다.
자바스크립트에서 주로 오디어, 이미지, 영상 등의 데이터를 다룰 때 사용한다. (참조 블로그)
메타데이터란?
데이터에 관한 구조화된 데이터로, 다른 데이터를 설명해주는 데이터다. 메타데이터란 단어가 무슨 뜻인지 알려주는 이 설명글 같다고 보면 된다. 대량의 정보 가운데에서 찾고 있는 정보를 효율적으로 찾아내서 이요하기 위해 일정한 규칙에 따라 콘텐츠에게 부여되는 데이터 (참조 사이트)
// fetch 예시
async function submit() {
  let imageBlob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png'));

  let formData = new FormData();
  formData.append("firstName", "Bora");
  formData.append("image", imageBlob, "image.png");

  let response = await fetch('/article/formdata/post/image-form', {
    method: 'POST',
    body: formData
  });
  let result = await response.json();
  alert(result.message);
}

 

 

 

 

 

 

formData 값 확인하기

전송한 값을 확인하려면 console.log를 사용해서 확인할텐데 FormData는 그렇게 확인할 수 없다.

왜냐하면 자바스크립트에서 FormData란 XMLHttpRequest 전송을 위해 설계된 특수한 객체 형태기때문에 간단하게 문자열화할수 없다. 그래서 console.log로 출력된 값에서는 key나 value값을 확인할 수 없다. 그럼 값을 확인하고 싶을때는 어떻게 해야할까.

 

여러개의 폼 데이터들은 기본적으로 iterable하기때문에 for문으로 순회해서 폼 데이터 객체에 어떤 값이 있는지 확인할 수 있다.

iterable (반복가능한)란?
이터러블한 객체( = 반복가능한 객체)의 대표적인 예로는 배열이 있다. 이터러블 개념을 사용하면 어떤 객체든 for...of 반복문을 적용할 수 있다. (참조 블로그)
let formData = new FormData();
formData.append('key1', 'value1');
formData.append('key2', 'value2');
 
// 폼 객체 key 값을 순회.
let keys = formData.keys();
for (const pair of keys) {
    console.log(pair); 
}
 
// 폼 객체 values 값을 순회.
let values = formData.values();
for (const pair of values) {
    console.log(pair); 
}
 
// 폼 객체 key 와 value 값을 순회.
let entries = formData.entries();
for (const pair of entries) {
    console.log(pair[0]+ ', ' + pair[1]); 
}

 

 

 

 

 

formData 값을 객체로 받기

만약 객체형태로 값을 받고싶다면 다음과 같이 리팩토링 할 수 있다.

// 폼데이터에 넣을 key-value 값들을 객체로 관리
const obj = {
    first: 'Akash',
    middle: 'Rishi',
    last: 'Mittal',
}
    
const formData = new FormData();
 
Object.entries(obj).forEach(item => formData.append(item[0], item[1]));
// 성능을 따진다면, 고차 함수 대신 for문을 이용해도 된다.
// for(let key in obj) {
//   formData.append(key, obj[key])
// }
 
// 폼데이터 값 출력
let entries = formData.entries();
for (const pair of entries) {
    console.log(pair[0]+ ', ' + pair[1]); 
}

 

 

참고블로그1, 참고블로그2

 

 

댓글