본문 바로가기

Computer Science/FE 지식

[WEB] Multipart/form-data

Multipart/form data의 정의

rfc1341 문서에서 multipart content-type을 아래와 같이 정의하고 있다.

A "multipart" Content-Type value, which can be used to combine several body parts, possibly of differing types of data, into a single message.

 

즉, 여러 종류의 데이터를 하나의 메시지로 결합하여 보낼 수 있는 헤더 필드로 공식적인 MIME(Multipurpose Internet Mail Extensions) 타입입니다.

 

Multipart 형태로 요청을 보낼 경우, http 프로토콜의 바디 부분에 데이터를 여러 파트로 나눠서 보내게됩니다. 일반적으로 파일 또는 이미지 등을 전달할 때 많이 씁니다. (file, fileName, file에 대한 부가정보들은 각각 file, string, etc.... 로 모두 type이 다르다. 이런 형태를 한 번에 보낼 수 있는 방법은 Multipart 형태가 적합하다.)

 

HTTP data 전송 방식

http 요청 / 응답의 구조

http는 StartLine, Header, Empty line, Body로 이루어져있습니다.

  • Start Line : HTTP 메서드, 타겟(URL, 포트, 도메인), HTTP 버전 을 알려줍니다.
  • HTTP Headers : 요청/응답에 대한 메타데이터 및 제약 조건(인증, 타입) 등에 대한 정보를 제공합니다.
  • Empty Line : header와 body를 명확하게 구분하기 위해서 존재합니다.
  • body : 요청/응답에 필요한 실제 데이터를 담고 있습니다. 이 때, 전송되는 데이터를 payload 라 부릅니다.(body의 데이터를 payload라 봐도 됩니다.) 데이터가 없을 경우, body는 비어있기도 합니다.

 

이 때, 멀티파트임을 알리는 `Content-Type :multipart/form data` 는 Header에 들어있으며 multipart data는 body의 payload에 있게됩니다.

 

 

Multipart/form-data 전송 방식

텍스트, boolean, file 형식의 Multipart/form-data를 전송 시 나오는 http 요청

POST / HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive 
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=---------------------------8721656041911415653955004498
Content-Length: 465

-----------------------------8721656041911415653955004498
Content-Disposition: form-data; name="myTextField"

Test
-----------------------------8721656041911415653955004498
Content-Disposition: form-data; name="myCheckBox"

on
-----------------------------8721656041911415653955004498
Content-Disposition: form-data; name="myFile"; filename="test.txt"
Content-Type: text/plain

Simple file.
-----------------------------8721656041911415653955004498--

일반적인 전송방식과 다르게 멀티파트는 여러 종류의 데이터를 하나의 메시지에 담아서 보냅니다. 그런데 이 파일들은 타입과 정보들이 모두 다르기 때문에, 이 파일들을 구분할 필요가 있습니다. 그 역할을 boundary가 해줍니다.

 

위 예제에서 처럼, -----를 이용하여 여러 데이터를 구분하고 있습니다. 마지막 줄은 --로 끝나는데 이는 boundary의 종료로 body가 끝났음을 알려줍니다.

 

위에서 설명했듯, Content-Type은 Header에, Data(payload)는 body에 담깁니다. 

 

요청 헤더의 정보, 당연히, 데이터의 정보는 여기 담겨있지 않다.
payload 탭에 multipart 데이터 정보가 들어있다.

이전에 이 데이터가 왜 http에 없을까 오래 고민하였는데, boundary 아래부분은 data이기때문에 payload에 담긴다는 것을 몰라서 Header만 보다가 시간을 한참 날렸었다.

 

※ http content-type은 default값이 application/json인데 multipart 형태로 보낼경우 자동으로 바뀌게 된다.

 

FormData 객체

js는 "multipart/form-data" 형태로 보낼 수 있도 FormData 객체를 지원한다. FormData 객체는 기본적으로 key/value 형식의 필드를 가집니다. 이를 통해서 쉽게 multipart/form-data를 구현할 수 있습니다.

      const form = new FormData();
      const selectedFile = document.getElementById('sell').files[0];
      form.append('image', selectedFile);
      form.append('name', 'devysi')

다만, FormData는 console.log에서는 내부 값을 확인할 수 없습니다.

비어있다....!

그래서, FormData의 내장 함수를 이용하여서 확인해야합니다.

   form.forEach((value, key) => {
      console.log(`key: ${key}    /    value: ${value}`);
   });

잘 찍힌다.

참고자료

ietf - rfc1341 : https://datatracker.ietf.org/doc/html/rfc1341

mdn- formdata : https://developer.mozilla.org/en-US/docs/Web/API/FormData

mdn- http message : https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages

blog - payload data : https://solace.com/blog/inside-a-solace-message-part-3-payload-data/

blog - multipart 원리 설명 글 : https://lng1982.tistory.com/209

blog - multipart 탄생 관련 글 : https://velog.io/@shin6403/HTTP-multipartform-data-%EB%9E%80