Jmeter에서 파일과 json을 동시에 보내기 위해 이런 저런 것들을 변경하다 보니 multipart/form-data가 무엇인지에 대해 궁금증이 생겼다.
json을 전송할 때에는 Content-Type을 application/json으로 설정하면 되고, 파일을 전송할 때는 multipart/form-data로 설정했는데 그럼 두개를 동시에 보낼 때는 어떤 것으로 설정해야 하는 것일까?
우선, 이미지 파일은 바이너리로 구성된 것이므로 png나 jpg 파일 자체가 전송되는 것이 아니라 바이너리가 HTTP request body에 담아 전송된다.
그리고 바이너리는 그 자체로 전송 시 효율이 높기 때문에 인코딩을 하지 않아도 된다.
enctype 속성이 multipart/form-data로 설정된 경우, form은 전송할 데이터를 MIME(Multipurpose Internet Mail Extensions) 형식으로 인코딩한다.
multipart/form-data는 여러 부분(parts)으로 나뉘어진 데이터를 전송하기 위한 형식으로, 파일 업로드와 같이 이진(binary) 데이터를 효과적으로 처리할 수 있다.
POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="username"
JohnDoe
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="profile_picture"; filename="profile.jpg"
Content-Type: image/jpeg
(Binary image data goes here)
------WebKitFormBoundaryABC123--
multipart/form-data로 전송된 request는 각 파트마다 바운더리로 구분되어 있으며, 개별적으로 명시된 Content-Type으로 처리된다. Content-Type이 명시되지 않은 경우 해당 데이터는 폼 필드로 처리된다.
그런데 파일은 인코딩이 필요 없다고 해도, 텍스트도 그냥 multiaprt/form-data로 전송해도 되는 것일까?
된다! 텍스트 데이터는 인코딩되지 않고 단순히 원본 문자열 그대로 전송된다.
그렇다면 맨 처음 질문으로 돌아와서, Base64로 인코딩한 이미지의 문자열을 json에 담아서 application/json 보내는 방법은 어떨까?
이 방법은 적은 용량의 파일을 보낼 때는 가능하다.
json 규격 자체에 maxSize에 대한 명세는 없으나, Json Parser에서 보통 4MB까지만 지원하므로 그냥 맘 편히 multipart/form-data를 사용하는 것이 좋다.
(물론 요구사항에 따라 필요할 수 있으므로, 알아 두는 것은 좋다!)
보통 json만 전송할 때에는 @RequestBody 어노테이션을 사용하는 것과 달리 multipart/form-data로 전송할 때는 @RequestPart를 사용해야 한다.
@RequestBody는 주로 json이나 xml과 같은 본문(body)에 직렬화된 데이터를 처리할 때 사용되므로, multipart로 오는 다양한 형태의 데이터를 모두 @RequestBody로 받는 것은 어렵다.
사용 예제는 다음과 같다.
@PostMapping(value = "/test")
public ResponseDto<RecipeResponseDto.RecipeStatusDto> testCreateRecipe(
@RequestPart(value = "content") RecipeRequestDto.CreateRecipeDto request,
@RequestPart(value = "thumbnail") MultipartFile thumbnail,
@RequestPart(value = "stepImages") List<MultipartFile> stepImages) {}