2025. 6. 20. 09:00ㆍJavascript/Javascript
보통 서버에 데이터를 전송하기 위해 아래와 같이 HTML5의 <form>을 이용해 구성하여 제출해 본 경험들이 있을 것이다.
<form action="./login" method="post">
<strong>아이디</strong>
<input type="text" name="name" value="아이디 입력">
<strong>비밀번호</strong>
<input type="password" name="password" value="비밀번호 입력">
<strong>성별</strong>
<input type="radio" name="gender" value="M">남자
<input type="radio" name="gender" value="F">여자
<strong>응시분야</strong>
<input type="checkbox" name="part" value="eng">영어
<input type="checkbox" name="part" value="math">수학
<input type="submit" value="제출">
</form>
이처럼 보통은 HTML5의 <form>을 이용해 input 값을 서버에 전송하지만 자바스크립트에서는 FormData()를 이용해 동일하게 스크립트로도 전송할 수 있다.
즉 FormData란 HTML이 아닌 자바스크립트 영역에서 폼 데이터를 다루는 객체라고 할 수 있다. 그리고 HTML에서의 submit 제출 동작은 Ajax를 통해 서버에 제출하는 것으로 이해할 수 있다.
let formData = new FormData(); // new FromData()로 새로운 객체 생성
formData.append('item','hi'); // <input name="item" value="hi">와 동일.
formData.append('item','hello'); // <input name="item" value="hello">와 동일.
FormData의 활용
HTML에서도 충분히 form을 다룰 수 있는데 왜 굳이 자바스크립트까지 와서 FormData를 다루는지 와닿지 않을 수도 있다. 사실 자바스크립트에서 Ajax로 form을 전송하는 일은 거의 없다고 볼 수도 있다.
하지만 HTML이 아닌 자바스크립트 영역에서 form 전송이 필요한 경우가 있는데 이미지 같은 멀티미디어 파일을 페이지 전환 없이비동기로 제출하고 싶은 경우나 자바스크립트를 통해 보다 타이트하게 form 데이터를 관리하고 싶을 때 이 FormData 객체를 이용한다.
// 자바스크립트로 직접 form 태그를 생성
let formData = new FormData(); // 새로운 폼 객체 생성
formData.append('item','hi'); // <input name="item" value="hi">와 동일.
formData.append('item','hello'); // <input name="item" value="hello">
// 만일 HTML에 이미 form 태그가 있으면 제이쿼리나 자바스크립트로 가져올 수도 있다.
// 제이쿼리인 경우
let formData1 = new FormData($("#formId"));
// 자바스크립트로 가져 올 경우
let formData2 = new FormData(document.getElementById("formId"));
위처럼 form 객체에 append() 메서드로 key와 value를 차례로 추가해 주면 곧 input 태그에 값을 입력하는 것과 같은 효과를 가진다. 참고로 값은 무조건 문자열로 자동 변환된다. 객체나 배열 같은 복잡한 데이터는 넣을 수 없다. 만약 문자열 이외의 데이터 타입을 넣으면 무시되고 문자열로 자동 변환되는 것이다.
FormData 사용법
formData.append(name, value)
// form의 name과 value를 필드에 추가
// 각각 input의 name 속성과 value 입력 값 역할을 한다고 생각 하면 된다.
formData.append(name, blob, fileName)
// input의 type이 'file'인 경우에 사용
// fileName은 file의 이름의 해당
formData.delete(name)
// 주어진 name으로 필드를 제거
formData.get(name)
// 주어진 name에 해당하는 필드의 value를 반환
formData.getAll(name)
// append 함수로 추가 시 name이 중복 가능
// 따라서 주어진 name에 해당하는 필드의 모든 value를 반환
formData.has(name)
// 주어진 name에 해당하는 필드가 있을 경우 true, 없으면 false를 반환
formData.set(name, value)
formData.set(name, blob, fileName)
// set 함수는 append 함수처럼 필드를 추가
// set도 추가를 해 주기는 하지만 기존 key가 있으면 그 key값을 모두 덮어쓴다
위의 메서드들을 아래와 같이 활용할 수 있다.
let formData = new FormData(); // 새로운 폼 객체 생성
formData.append('item', 'hi');
// key가 존재하는지 확인. 값이 boolean type으로 반환됨.
formData.has('item'); // true.
formData.has('money'); // false
// 값의 첫 번째 값이 반환됨.
formData.get('item'); // hi.
// 중복된 key값을 모두 가져올 때 배열 형식으로 가져옴.
formData.append('item', 'hello'); // 똑같은 item key에 값을 또 추가
formData.getAll('item'); // ['hi','hello']
// 중복된 값을 넣을 때에는 배열로 한꺼번에 append할 수 있다.
formData.append( 'test', ['hi','hyemin'] );
formData.get('test'); // hi,hyemin
// 삭제
formData.delete('test');
formData.get('test'); // null 값이 들어간다.
// item 값을 수정한다.
formData.set('item','test2');
formData.getAll('item); // ['test2']
FormData 값의 콘솔 출력
FormData 객체를 생성하고 append를 통해 key와 value를 아주 많이 넣었다고 가정해 보자. 그리고 어떠한 폼 데이터들을 넣었는지 확인하고 싶을 때 console.log()를 통해 출력해 볼 수 있을 것이다.
하지만 다음 이미지와 같이 폼 데이터의 keys와 values들은 어디에서도 확인할 수 없다.
자바스크립트에서 FormData란 단순한 객체가 아니며 XMLHttpRequest 전송을 위해 설계된 특수한 객체 형태이기 때문이다. 그래서 간단히 문자열화할 수 없어 console.log를 통한 확인이 불가능한 것이다. 하지만 그렇다고 확인할 수 있는 방법이 전혀 없는 것은 아니다.
FormData 값 순회하기
여러 개의 폼 데이터들은 기본적으로 iterable하기 때문에 for문으로 순회할 수도 있다. 그리고 이를 통해 폼 데이터 객체에 어떠한 값들이 들어 있는지 확인이 가능하다.
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에 이미지 담기
이미지와 같은 멀티미디어 파일을 폼 데이터에 담고 싶다면 아래 코드와 같이 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(){
var formData = new FormData();
// form Data 객체 생성
formData.append("attachedImage", fileInput.files[0]);
// 파일 인풋에 들어간 파일들은 files 라는 리스트로 저장된다.
// input에 multiple을 선언해 여러개의 파일을 선택한 경우가 아니라면 files[0] 으로 input에 추가한 파일 객체를 찾을 수 있다.
});
</script>
</body>
FormData 값을 객체로 받기
이번에는 보다 심화된 응용 예제이다. 만약 폼 데이터에 넣을 key-value 값들을 객체로 관리하고 싶은 경우 다음과 같이 리팩토링할 수 있다.
// 폼데이터에 넣을 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]);
}
/**
first, Akash
middle, Rishi
last, Mittal
*/
반대로 FormData 객체의 폼 데이터를 자바스크립트 객체로 환원도 가능하다.
const obj2 = {};
formData.forEach((value, key) => obj2[key] = value);
console.log(obj2); // {first: 'Akash', middle: 'Rishi', last: 'Mittal'}
FormData 서버 전송하기
본래 HTML에서 폼 데이터를 서버로 보낼 때에는 다음과 같이 action과 method 속성 부분을 정의해서 input의 submit으로 보냈다.
<form action="/action_page.php" method="get">
<input type="text" id="fname" name="fname"><br><br>
<input type="text" id="lname" name="lname"><br><br>
<input type="submit" value="Submit">
</form>
그러나 FormData는 자바스크립트 클래스이므로 서버에 전송하기 위해서는 fetch api를 사용해야 한다.
fetch api로 폼 데이터 전송하기
여기서 유의해야 할 점은 자바스크립트에서 서버로 FormData를 보내려면 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);
});
cf) FormData를 보낼 때 header 부분은 브라우저가 자동으로 설정해 주기 때문에 Content-Type을 application/x-www-form-urlencoded... 등으로 따로 지정할 필요가 없다.
URLSearchParams
만일 위처럼 FormData 객체에 일일이 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);
});
'Javascript > Javascript' 카테고리의 다른 글
[Javascript] spread와 rest (1) | 2025.06.24 |
---|---|
[Javascript] 비구조화 할당(구조분해) (1) | 2025.06.23 |
[Javascript] 객체: 생성자 함수 (1) | 2025.06.19 |
[Javascript] async 함수의 병렬 처리 (1) | 2025.06.18 |
[Javascript] 가비지 컬렉션(Garbage Collection) (1) | 2025.06.17 |