FormData와 multipart/form-data

김현중·2024년 8월 12일

연구소

목록 보기
5/34
post-thumbnail

웹 개발에서 파일을 서버로 전송하는 일이 자주 있다. 이미지를 업로드하거나, CSV 파일을 제출하거나, 여러 파일을 한 번에 전송하는 일이 있는데, 이런 작업을 처리할 수 있도록 도와주는 'FormData'와 'multipart/form-data' 방식이 있다.


FormData

FormData는 브라우저에서 제공하는 웹 API로, HTML 폼 데이터(파일 포함)를 쉽게 만들고, 이를 서버에 전송할 수 있게 해준다. 파일뿐만 아니라 텍스트 데이터도 함께 전송할 수 있으며, 다양한 데이터를 동시에 처리해야 하는 상황에서도 사용된다.

특징

  • 파일 업로드 : 파일을 쉽게 서버에 전송할 수 있다.
  • 다양한 데이터 타입 지원 : 파일뿐 아니라 텍스트, 숫자 등 다양한 타입의 데이터를 함께 전송할 수 있다.
  • 브라우저 호환성 : 대부분의 브라우저에서 지원된다.


multipart/form-data

multipart/form-data는 주로 파일 업로드에 사용되는 HTTP 프로토콜의 인코딩 방식이다. 일반적인 폼 데이터는 'application/x-www-form-urlencoded' 방식으로 인코딩 되지만, 파일과 같은 바이너리 데이터를 전송할 때에는 'multipart/form-data' 방식이 사용된다.

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와 multipart/form-data를 이용한 파일 업로드 예제

클라이언트

사용자가 선택한 파일을 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>
	);
}
  1. 사용자가 파일을 선택하면 handleFileChange 함수가 호출되어 파일이 file 상태에 저장된다.
  2. 사용자가 파일 업로드 버튼을 누르면 handleSubmit 함수가 호출되고, FormData 객체가 생성되어 파일이 추가된다.
  3. fetch를 사용해 서버로 POST 요청을 보내며, body에 FormData 객체를 담아 전송한다. 이때, 요청은 multipart/form-data 형식으로 서버에 전달된다.

서버

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 });
  });
}
  1. formidable 라이브러리를 사용해 multipart/form-data로 전송된 파일을 파싱하고, 파일을 서버에 저장한다.


결론

FormData와 multipart/form-data는 웹에서 파일과 데이터를 함께 전송할 때 매우 유용한 도구이다. FormData는 클라이언트 측에서 파일을 쉽게 서버로 전송할 수 있도록 도와주며, multipart/form-data는 이러한 파일과 데이터를 안전하고 효율적으로 처리할 수 있는 인코딩 방식이다.

profile
박수 받는 사람이 되고 싶어서 항상 노력합니다.

0개의 댓글