파일 여부나 추가 필드 여부 등과 상관없이 통용되는
HTML 폼 전송 방법
설명
FormData 는 폼을 쉽게 보내도록 도와주는 객체입니다.
이름을 보고 유추하셨듯이 FormData 객체는 HTML 폼 데이터를 나타냅니다.
생성자는 다음과 같습니다.
let formData = new FormData([form]);
HTML 에 form 요소가 있는 경우, 위와 같은 코드를 작성하면 해당 폼 요소의 필드 전체가 자동 반영됩니다.
fetch 등의 네트워크 메서드가 FormData 객체를 바디로 받는다는 건 FormData 의 특징입니다.
이때 브라우저가 보내는 HTTP 메시지는 인코딩되고 Content-Type 속성은 multipart/form-data 로 지정된 후 전송됩니다.
서버 관점에서는 FormData 를 사용한 방식과 일반 폼 전송 방식에 차이가 없습니다.
간단한 폼 전송하기
간단한 폼을 전송한다고 가정해 봅시다.
<form id="formElem">
<input type="text" name="name" value="Bora">
<input type="text" name="surname" value="Lee">
<input type="submit">
</form>
<script>
formElem.onsubmit = async (e) => {
e.preventDefault();
let response = await fetch('/article/formdata/post/user', {
method: 'POST',
body: new FormData(formElem)
});
let result = await response.json();
alert(result.message);
};
</script>
FormData 메서드
FormData 에 속하는 필드는 아래와 같은 메서드로 수정할 수 있습니다.
1. formData.append(name, value)
name 과 value 를 가진 폼 필드를 추가
2. formData.append(name, blob, fileName)
<input type="file"> 형태의 필드를 추가, 세 번째 인수 fileName 은 사용자가 해당 이름을 가진 파일을 폼에 추가한 것처럼 설정해 줍니다.
3. formData.delete(name)
name 에 해당하는 필드를 삭제합니다.
4. formData.get(name)
name 에 해당하는 필드의 값을 가져옵니다.
5. formData.has(name)
name 에 해당하는 필드가 있다면 true , 그렇지 않으면 false 를 반환합니다.
폼은 이름(name) 이 같은 필드 여러 개를 허용하기 때문에 append 메서드를 여러 번 호출해 이름이 같은 필드를 계속 추가해도 문제가 없습니다.
append 메서드 이외에 필드 추가 시 사용할 수 있는 메서드로 set 도 있습니다. set 이 append 메서드와 다른 점은 set 은 name 과 동일한 이름을 가진 필드를 모두 제거하고 새로운 필드 하나를 추가한다는 데 있습니다.
따라서 set 메서드를 쓰면 name 을 가진 필드가 단 한개만 있게끔 보장할 수 있습니다.
이 외에 다른 기능은 append 와 동일합니다.
- formData.set(name, value)
- formData.set(name, blob, fileName)
또한 폼 데이터 필드에 반복 작업이 필요할 땐 for..of 루프를 사용할 수 있습니다.
let formData = new FormData();
formData.append('key1', 'value1');
formData.append('key2', 'value2');
// key/value 쌍이 담긴 리스트
for(let [name, value] of formData) {
alert(`${name} = ${value}`); // key1 = value1, then key2 = value2
}
파일이 있는 폼 전송하기
폼을 전송할 때 HTTP 메시지의 Content-Type 속성은 항상 multipart/form-data 이고 메시지는 인코딩되어 전송됩니다.
파일이 있는 폼도 당연히 이 규칙을 따르기 때문에 <input type="file"> 로 지정한 필드 역시 일반폼을 전송할 대와 유사하게 전송됩니다.
<form id="formElem">
<input type="text" name="firstName" value="Bora">
Picture: <input type="file" name="picture" accept="image/*">
<input type="submit">
</form>
<script>
formElem.onsubmit = async (e) => {
e.preventDefault();
let response = await fetch('/article/formdata/post/user-avatar', {
method: 'POST',
body: new FormData(formElem)
});
let result = await response.json();
alert(result.message);
};
</script>
Blob 데이터가 있는 폼 전송하기
이미지 같은 동적으로 생성된 바이너리 파일은 Blob 객체를 사용해 쉽게 전송할 수 있습니다.
이때 Blob 객체는 fetch 메서드의 body 매개변수에 바로 넘겨줄 수 있습니다.
Blob (Binary Large Object)
이진 데이터를 다루기 위한 객체입니다.
파일 데이터, 이미지, 오디오, 비디오, 또는 텍스트 데이터와 같은 큰 데이터 덩어리를 브라우저에서 처리하거나 서버와 주고받을 때 사용합니다.
즉, 대량의 이진 데이터를 다룰 수 있게 해주는 객체입니다.
그런데 실제 코딩을 하다 보면 이미지를 별도로 넘겨주는 것 보다 폼에 필드를 추가하고 여기에 이미지 이름 등의 메타데이터를 같이 실어 넘겨주는게 좀 더 편리합니다.
서버 입장에서도 원시 바이너리 데이터를 받는 것보다 multipart-encoded 폼을 받는게 좀 더 편하고 적합합니다.
formData.append(name, blob, fileName);
1. name
폼 필드의 이름입니다. 서버에서 이 이름을 통해 데이터를 참조합니다.
2. blob
파일 데이터(내용) 입니다.
File 객체, Blob 객체, 또는 다른 데이터 형식(텍스트 등) 을 넣을 수 있습니다.
3. fileName
서버에서 이 파일을 받을 때 사용자가 업로드한 파일 이름처럼 설정됩니다.
즉, 사용자가 파일을 업로드하지 않았더라도, 특정 이름을 가진 파일이 서버로 전송되는 것처럼 보이게 합니다.
fileName 은 필드 이름이 아닙니다.
필드 이름(name) : 서버에서 폼 필드 데이터를 참조할 때 사용하는 이름입니다.
파일 이름(fileName) : 전송된 파일의 이름입니다. 서버는 이 이름을 사용해 파일을 저장하거나 처리합니다.
const formData = new FormData();
// HTML Input으로부터 파일 가져오기
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];
// FormData에 파일 추가
formData.append('profileImage', file, 'renamedImage.png');
// 전송
fetch('https://example.com/upload', {
method: 'POST',
body: formData,
});
1. profileImage
서버에서 폼 필드로 참조할 이름
2. file
사용자가 선택한 파일 데이터
3. renamedImage.png
서버에서 파일 이름을 참조
이렇게 서버는 파일 이름을 renamedImage.png 로 인식하며, 사용자가 이 이름의 파일을 업로드한 것처럼 처리합니다.
// node express 예시
app.post('/upload', upload.single('profileImage'), (req, res) => {
// 파일 정보
console.log('파일 이름:', req.file.originalname);
console.log('파일 경로:', req.file.path);
console.log('필드 이름:', req.file.fieldname);
// 추가적으로 FormData의 다른 데이터도 받을 수 있음
console.log('폼 데이터:', req.body);
res.json({ message: '파일 업로드 성공!', file: req.file });
});
'JavaScript' 카테고리의 다른 글
jQuery (0) | 2024.11.27 |
---|---|
Chrome 으로 기초 디버깅 (1) | 2024.10.29 |
JavaScript 최신 문법 정리 (0) | 2024.10.28 |