multipart/form-data가 뭐야?
이미지 업로드를 구현하다 보면 'multipart/form-data'라는 것을 마주하게 됩니다.
form을 쓰든, axios로 리소스를 바로 전송하든 바이너리 데이터를 전송할 때 multipart/form-data로 Content-Type을 설정해 주어야 합니다.
왜 이미지 등 파일을 업로드 할 때 multipart/form-data를 사용하는 걸까요?
multipart/form-data는 무엇일까요?
form이라는 태그가 있습니다. form 태그는 서버로 보내질 입력 양식 전체를 감싸는 태그입니다. name, action, method, autocomplete, enctype를 속성으로 가지고 있지요.
<form action="/home/uploadfiles" method="post" enctype="multipart/form-data">
파일명 : <input type="file" name="myfile">
<button type="submit">제출하기</button>
</form>
- name : 서버로 보내질 데이터의 변수명
- action : form이 전송되는 서버 url 또는 html 링크
- method : 전송 방법으로 get이 기본
- autocomplete : 자동 완성 기능으로 'on'으로 하면 form 전체에 자동 완성을 허용
- enctype: 폼 데이터를 서버로 전송할 때 해당 데이터가 인코딩 되는 방식
인코딩?
컴퓨터는 0과 1로만 이루어진 이진수만 이해할 수 있습니다. 그래서 컴퓨터는 문자를 그대로 이해할 수 없습니다. 컴퓨터에서 'ㄱ,ㄴ,ㄷ'이나 'a, b, Z,T' 등의 문자를 표시하기 위해 각각의 문자를 숫자로 지정해 줄 필요가 있었습니다. 한 문자에 해당하는 숫자를 지정하면 그 값을 이진수로 변환해서 컴퓨터가 각 문자를 식별할 수 있게 하는 겁니다.
컴퓨터마다 이런 문자에 대한 숫자 값이 다르면 컴퓨터 간에 데이터를 교환할 때 컴퓨터마다 다른 문자가 표출 될 수 있습니다. 그렇기 때문에 'ANSI'라는 표준을 정하는 곳에서 각 문자에 해당하는 숫자 값을 하나로 통일시키며 표준을 만들었습니다. 그것이 바로 ASCII(American Standard Code for Information Interchange, 정보 교환을 위한 미국 표준 코드)입니다.
문자를 그대로 이해할 수 없는 컴퓨터간에 텍스트 파일을 주고 받는데는 ASCII라는 공통 표준을 따르면 아무 문제가 없습니다. 하지만 우리는 문자로 된 텍스트 파일만 주고 받지 않습니다. 음악 파일, 영상 파일, 그림 파일, 워드 프로세서 문서 파일 등 바이너리(binary) 파일을 보내야 하는 경우도 있습니다.
이메일이나 가상 네트워크 상에서 데이터를 교환하는 시스템은 ASCII로 이루어진 파일만을 전송하는 것을 전제로 제작되었습니다. ASCII는 7비트인데, 바이너리 파일은 8비트 입니다. 즉, 이진수로 했을때 ASCII는 7자리, 바이너리 데이터는 8자리로 자릿수가 다릅니다. 7비트인 ASCII 문자로만 이루어진 파일을 주고 받도록 구현된 기존 시스템에서는 8비트인 바이너리 데이터를 제대로 전달 수 없습니다.
바이너리 데이터를 문제 없이 전달하기 위해서 8비트 바이너리 데이터를 다시 7비트의 ASCII 문자 파일로 바꾸는 작업이 필요해 졌습니다. 이렇게 바이너리 파일을 텍스트 파일로 바꾸는 것을 '인코딩(encoding)'이라고 합니다. 반대로 인코딩 된 텍스트 파일을 다시 바이너리 파일로 변환하는 것은 '디코딩(decoding)'이라고 합니다. 여러 인코딩 방식을 통해 바이너리 파일은 아스키 문자 파일이 되어 원래의 시스템을 타고 문제 없이 전달 될 수 있습니다.
서버로 바이너리 데이터를 전달 할 때 컴퓨터가 이해할 수 있도록 인코딩 과정을 거쳐야 합니다. 그래서 데이터를 서버로 전송하는 태그인 form은 enctype이라는 속성을 갖습니다. 이 요소의 값으로 인코딩 방식을 설정합니다.
- enctype 속성 값
- application/x-www-form-urlencoded : enctype 속성의 기본 값, 모든 문자들을 서버로 보내기 전 인코딩 함
- text/plain : 공백 문자(space)만 '+' 기호로 변환하고 나머지 문자는 모두 인코딩 하지 않음
- multipart/form-data : 모든 문자를 인코딩 하지 않음, 파일이나 이미지를 서버로 전송할 때 주로 사용
enctype 속성은 HTML 폼 전송으로 POST 요청을 보낼 때 요청의 Content-Type을 지정합니다.
Content-Type?
Content-Type은 헤더 개체이며 리소스의 미디어 타입(media type)을 나타내기 위해 사용합니다.
요청(request) 내에 있는 Content-Type 헤더는 클라이언트가 서버에게 어떤 유형의 데이터를 전송했는지를 알려주고, 응답(response) 내에 있는 Content-Type 헤더는 서버가 클라이언트에게 반환한 컨텐츠의 유형이 무엇인지 알려줍니다.
Content-Type은 media-type; charset; [boundary] 구조로 되어있습니다.
Content-Type: text/html; charset=utf-8
Content-Type: multipart/form-data; boundary=something
- media-type : 리소스 혹은 데이터의 MIME type
- charset : 문자 인코딩 표준
- boundary : 멀티파트 개체일 경우 필수, 메시지의 멀티 파트 경계선을 캡슐화하기 위해 사용
Content-Type의 media-type, 즉 리소스 혹은 데이터가 어떤 유형인지는 MIME type을 사용합니다.
" MIME type은 문서, 파일 또는 바이트 집합의 성격과 형식을 나타낸다"
MIME? MIME type?
MIME(Multipurpost Internet Mail Extensions)은 일종의 인코딩 방식입니다. MIME은 이름에 'Internet Mail'이라는 단어가 들어가 있는 것처럼 이메일과 함께 보낼 첨부 파일을 텍스트 문자로 전환하기 위해 개발되었습니다.
초기의 대표적인 인코딩 표준 방식은 UUEncode(Unix-to-Unix Encode)였습니다. UUEncode 방식은 문서 끝 부분의 공백이 사실 공백이 아니라 변경되어야 할 값인데 공백을 무시하는 시스템의 경우 UUEncode 파일의 원형을 그래도 받을 수 없는 경우가 생겼다고 합니다. 그래서 UUEncode의 방식을 대폭 보강하여 나온 새로운 인코딩 방식이 MIME인 것입니다.
MIME에서 사용하는 인코딩 방식을 'base64'라고 하며, MIME는 파일 포맷 정보도 함께 담을 수 있어 지금 전달하는 파일이 GIF인지, MOV인지 파일의 종류를 나타내는 딱지를 붙일 수 있습니다.
MIME type은 아래와 같은 구조로 되어있습니다.
text/plain
application/json
multipart/form-data
MIME type은 슬래시(/)로 구분된 'type'과 'subtype'으로 구성되어 있습니다. 그 중 type은 discrete와 multipart라는 두 가지 클래스가 있습니다.
discrete는 단일 파일이나 매체를 나타내는 타입입니다.
- discrete type
- application
- audio
- image
- text
- video
- ...
multipart는 여러 컴포넌트 조각으로 구성된 문서를 나타내는 타입입니다. 각 컴포넌트 부분은 고유한 개별 MIME type을 가질 수 있습니다. 또한 하나의 트랜잭션으로 함께 전송되는 여러 파일을 캡슐화 할 수 있습니다.
- multipart type
- message
- multipart
discrete는 하나의 문서 또는 파일의 성격과 형식을 나타낸다면 multipart는 여러 문서의 성격과 형식을 나타낼 수 있습니다. 또한 multipart 각 문서의 MIME type을 각각 줄 수도 있습니다.
HTTP 통신과 multipart/form-data
HTTP 헤더에 지정한 타입의 데이터가 Message Body에 담겨서 서버로 보내집니다. 보통 Message Body는 한 종류의 데이터 유형이 대부분이고 Content-Type도 하나의 타입만을 명시할 수 있습니다. 예를 들어 text이면 text/plain, xml이면 text/xml, png이미지이면 image/png 이런 식으로 명시하여 데이터를 서버로 전송하게 됩니다.
하지만 일반적인 파일 업로드 상황을 보면 이미지 등과 같은 바이너리 데이터만 전송하는 경우도 있지만 설명이나 다른 input 값들도 넘겨야 하는 경우가 더 많습니다.
이미지와 이미지 설명의 경우 이미지의 Content-Type은 'image/png'입니다. 이미지 설명의 Content-Type은 'application/x-www-form-urlencoded'가 될 겁니다.
두 종류에 대한 Content-Type이 하나의 HTTP Request Body에 들어가야 하는데 이때 2종류의 데이터를 구분해서 넣어주는 방법이 필요해졌고, 그 방법이 바로 multipart/form-data인 것입니다.
Content-Type을 multipart/form-data로 보낼 경우 데이터는 아래와 같은 형태로 서버에 전달 됩니다.
Content-Type: multipart/form-data; boundary=aBoundaryString
(other headers associated with the multipart document as a whole)
--aBoundaryString
Content-Disposition: form-data; name="myFile"; filename="img.jpg"
Content-Type: image/jpeg
(data)
--aBoundaryString
Content-Disposition: form-data; name="myField"
(data)
--aBoundaryString
(more subparts)
--aBoundaryString--
POST /foo HTTP/1.1
Content-Length: 68137
Content-Type: multipart/form-data; boundary=---------------------------974767299852498929531610575
Content-Disposition: form-data; name="description"
---------------------------974767299852498929531610575
some text
---------------------------974767299852498929531610575
Content-Disposition: form-data; name="myFile"; filename="foo.txt"
Content-Type: text/plain
(content of the uploaded file foo.txt)
---------------------------974767299852498929531610575--
Content-Type이 멀티파트 개체일 경우 boundary 디렉티브는 필수입니다. 이 boundary 디렉티브는 이중 대시(--)로 시작되는 문자열이며 메시지의 멀티 파트 경계선을 캡슐화 합니다. 즉 파일 간의 경계를 짓습니다.
정리
multipart/form-data를 설명하기 위해 많은 것을 거쳐왔습니다.
정리하자면 multipart/form-data는 바이너리 파일을 전달할 때 HTTP Header의 Content-Type으로 Message Body에 들어가는 데이터 유형을 명시하는 MIME type 중 하나 입니다.
multipart 클래스는 여러 컴포넌트 조각으로 구성되어 있고, 각 컴포넌트 마다 고유한 MIME type을 가질 수 있기 때문에 Content-Type이 하나의 타입만 명시할 수 있다는 한계점을 넘어 여러 파일 및 input 데이터의 Content-Type을 명시할 수 있습니다. 그래서 파일이나 이미지를 서버에 전송할 때 해당 인코딩 형식을 사용합니다.
[참고 자료]
https://velog.io/@shin6403/HTTP-multipartform-data-%EB%9E%80
HTTP multipart/form-data 란?
프로젝트를 진행하면서 프론트 -> 백엔드로 이미지를 전송하는 경우가 있었다.오늘은 HTTP, multipart, multipart/form-data 세 가지 키워드에 대해 알아보고, 그 중에서 중요한 개념중에 하나인 multipart/for
velog.io
https://developer.mozilla.org/ko/docs/Web/HTTP/Basics_of_HTTP/MIME_Types
MIME 타입 (IANA 미디어 타입) - HTTP | MDN
미디어 타입 (Multipurpose Internet Mail Extensions 또는 MIME type로도 알려져 있음)이란 문서, 파일 또는 바이트 집합의 성격과 형식을 나타냅니다. MIME 타입은 IETF의 RFC 6838에 정의 및 표준화되어 있습니다
developer.mozilla.org
https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Content-Type
Content-Type - HTTP | MDN
Content-Type 개체 헤더는 리소스의 media type을 나타내기 위해 사용됩니다.
developer.mozilla.org
마임 타입 (MIME Type), 미디어 타입(Media Type) 개괄
2000-9-16 아스키 (ASCII) 마임(MIME) 타입을 이해하기 위해서는 아스키와 바이너리에 대해 알고 있어야 하므로 먼저 간단하게 설명합니다. 컴퓨터는 0 과 1로 이뤄진 이진수만 이해할 수 있습니다. 바
ltvw.tistory.com