웹 개발에서 파일을 서버로 전송하는 일이 자주 있다. 이미지를 업로드하거나, CSV 파일을 제출하거나, 여러 파일을 한 번에 전송하는 일이 있는데, 이런 작업을 처리할 수 있도록 도와주는 'FormData'와 'multipart/form-data' 방식이 있다.
FormData는 브라우저에서 제공하는 웹 API로, HTML 폼 데이터(파일 포함)를 쉽게 만들고, 이를 서버에 전송할 수 있게 해준다. 파일뿐만 아니라 텍스트 데이터도 함께 전송할 수 있으며, 다양한 데이터를 동시에 처리해야 하는 상황에서도 사용된다.
특징
- 파일 업로드 : 파일을 쉽게 서버에 전송할 수 있다.
- 다양한 데이터 타입 지원 : 파일뿐 아니라 텍스트, 숫자 등 다양한 타입의 데이터를 함께 전송할 수 있다.
- 브라우저 호환성 : 대부분의 브라우저에서 지원된다.
multipart/form-data는 주로 파일 업로드에 사용되는 HTTP 프로토콜의 인코딩 방식이다. 일반적인 폼 데이터는 'application/x-www-form-urlencoded' 방식으로 인코딩 되지만, 파일과 같은 바이너리 데이터를 전송할 때에는 'multipart/form-data' 방식이 사용된다.
multipart/form-data는 폼 데이터를 여러 부분으로 나누어 전송하며, 각 부분은 특정 경계로 구분된다. 서버는 이 경계를 기준으로 각 파트를 구분하고, 그 내용을 처리하게 된다. 각 파트는 헤더와 본문으로 구성되며, 헤더에는 파일 이름, 타입 등이 포함된다.
예시
POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="username"
KimHyunJoong
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="example.txt"
Content-Type: text/plain
(content of the file)
------WebKitFormBoundary7MA4YWxkTrZu0gW--
여기서 '------WebKitFormBoundary7MA4YWxkTrZu0gW'는 각 파트를 구분하는 경계이다. 첫 번째 파트는 텍스트 데이터(username)이며, 두 번째 파트는 파일(example.txt)이다. 이러한 방식으로 다양한 데이터가 하나의 요청에서 전송될 수 있다.
사용자가 선택한 파일을 FormData 객체에 담아 서버로 전송한다.
import React, { useState } from 'react';
export default function FileUpload() {
const [file, setFile] = useState(null);
const handleFileChange = (e) => {
setFile(e.target.files[0]);
};
const handleSubmit = async (e) => {
e.preventdefault();
// FormData 객체 생성 및 파일 추가
const formData = new FormData();
formData.append('file', file);
try {
const response = await fetch('/api/upload', {
method: 'POST',
body: formData, // multipart/form-data 형식으로 전송
}));
await response.json();
} catch (error) {
// 에러 처리
}
};
return (
<form onSubmit={handleSubmit}>
<input type='file' onChange={handleFileChange} />
<button type='submit'>업로드</button>
</form>
);
}
API route를 사용하여 'multipart/form-data'요청을 처리한다.
import { NextApiRequest, NextApiResponse } from 'next';
import formidable from 'formidable';
import fs from 'fs';
export const config = {
api: {
bodyParser: false, // Next.js에서 기본 제공하는 bodyParser 비활성화 (formidable 사용)
},
};
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const form = formidable({ multiples: false }); // 단일 파일 업로드 설정
form.parse(req, (err, fields, files) => {
if (err) {
res.status(500).json({ error: '!파일 업로드 중 오류 발생!' });
return;
}
// 업로드된 파일 정보
const file = files.file as formidable.File;
const data = fs.readFileSync(file.filepath);
fs.writeFileSync(`./uploads/${file.originalFilename}`, data); // 파일 저장
res.status(200).json({ message: '!파일 업로드 성공!', fileName: file.originalFilename });
});
}
FormData와 multipart/form-data는 웹에서 파일과 데이터를 함께 전송할 때 매우 유용한 도구이다. FormData는 클라이언트 측에서 파일을 쉽게 서버로 전송할 수 있도록 도와주며, multipart/form-data는 이러한 파일과 데이터를 안전하고 효율적으로 처리할 수 있는 인코딩 방식이다.