multipart/form-data와 JSON 동시 처리

별빛사막·2025년 2월 28일
0

트러블슈팅

목록 보기
1/7
post-thumbnail

문제 발생

프로젝트 수정 시, 다음과 같은 세 가지 경우가 존재한다.

  1. 썸네일 첨부파일만 수정하는 경우
    Content-Type 'application/octet-stream' is not supported.
  2. 썸네일 첨부파일과 프로젝트 내용(JSON)도 수정하는 경우
    Content-Type 'application/json' is not supported.
  3. 프로젝트 내용(JSON)만 수정하는 경우
    Content-Type 'application/octet-stream' is not supported.

각각의 경우에서 415 Unsupported Media Type 오류가 발생했다

문제 원인

Spring Boot에서 415 Unsupported Media Type 오류가 발생한 이유는 Postman에서 deleteThumbnail 값을 Text로 보내지 않았을 가능성이 크다.

원인) Boolean 타입을 @RequestPart로 받을 경우 발생하는 문제

@RequestPart(value = "deleteThumbnail", required = false) Boolean deleteThumbnail,

위와 같이 Boolean을 @RequestPart로 받을 경우, Spring Boot는 multipart/form-data에서 Boolean 값을 직접 처리하지 못한다.

  • Boolean 값은 true 또는 false 값을 기대하지만, multipart/form-data는 기본적으로 String 또는 File 형태로 전달된다.
  • Postman에서 false를 입력해도 내부적으로 application/octet-stream으로 인식될 수 있다.
  • Spring Boot는 multipart/form-data 내에서 Boolean 값을 직접 변환하지 못해 오류가 발생한다.

💡 즉, Postman이 Boolean 값을 Text가 아닌 application/octet-stream 타입으로 보내면서 Spring Boot가 이를 지원하지 못한 것이다.

문제 해결 방법: String으로 수신 후 Boolean 변환

deleteThumbnailString으로 받고 Boolean으로 변환하여 사용하는 방식으로 해결했다.

@RequestPart(value = "deleteThumbnail", required = false) String deleteThumbnailStr, // ✅ String으로 받기

이제 deleteThumbnailString으로 받으면서 Postman이 데이터를 반드시 Text 형식으로 보내도록 강제할 수 있다.

  • Postman에서 "false"를 Text로 보내면, Spring Boot는 이를 String으로 처리할 수 있다.
  • 이후 Boolean으로 변환하여 사용하면 된다.
Boolean deleteThumbnail = deleteThumbnailStr != null && deleteThumbnailStr.equalsIgnoreCase("true");

이 방식은 Spring이 multipart/form-data를 더 자연스럽게 처리할 수 있도록 도와준다.


추가 학습

1. multipart/form-data와 JSON을 함께 처리하기 위한 원리

  • multipart/form-data는 여러 개의 데이터를 각각의 파트로 분리하여 전송하는 방식이다.
  • JSON과 파일을 함께 전송하려면 각각의 Content-Type을 적절하게 설정해야 한다.
  • Spring에서는 @RequestPart를 활용하여 JSON과 파일을 동시에 받을 수 있다.

2. @RequestParam vs @RequestPart

@RequestParam

  • 쿼리 파라미터, form 데이터, multipart/form-data 등의 요청 파라미터를 처리할 수 있다.
  • 메소드 인수가 String이나 multipart/form-data가 아닐 경우 등록된 Converter 또는 PropertyEditor를 통한 형식 변환에 의존한다.
  • Key/Value form 필드와 함께 사용된다.

@RequestPart

  • multipart/form-data에 특화되어 있으며 여러 복잡한 값을 처리할 때 사용할 수 있다.
  • 메소드 파라미터 타입이 String 또는 MultipartFile/Part가 아닐 경우, 요청 부분의 Content-Type 헤더를 고려하는 HttpMessageConverters에 의존한다.
  • JSON, XML 등을 포함하는 복잡한 Content를 포함하는 경우에 적합하다.

3. Spring의 Multipart 처리 방식

  • CommonsMultipartResolver vs StandardServletMultipartResolver 비교 → CommonsMultipartResolver는 Apache Commons FileUpload를 기반으로 동작하며, StandardServletMultipartResolver는 Servlet 3.0의 기본 Multipart 기능을 활용한다.
  • spring.servlet.multipart.enabled 설정 옵션 → true로 설정하면 Spring Boot에서 Multipart 요청을 자동으로 처리할 수 있다.

4. Postman에서 multipart/form-data 전송 시 고려해야 할 사항

  • 파일 전송 시 form-data 방식으로 설정하는 방법 → Postman에서 Body 탭에서 form-data 선택 후 Key에 파일명을 지정하고 Type을 File로 설정해야 한다.
  • Boolean 값 전달 시 Text로 설정해야 하는 이유 → multipart/form-data에서는 Boolean 값이 기본적으로 지원되지 않으므로 String으로 변환 후 처리해야 한다.

5. Spring에서 JSON을 처리하는 방법

  • @RequestBody vs @RequestPart 차이점 → @RequestBody는 JSON 전체 요청을 변환하고, @RequestPart는 Multipart 요청의 일부로 JSON을 처리한다.
  • HttpMessageConverter를 활용한 커스텀 변환 적용 방법 → Spring의 MappingJackson2HttpMessageConverter를 사용하면 JSON을 원하는 객체로 변환할 수 있다.

6. 파일 업로드 관련 보안 이슈

  • 업로드 파일의 Content-Type 검증 → 파일 확장자만 검증하는 것이 아니라 실제 Content-Type을 검사해야 한다.
  • 파일 크기 제한 설정 (spring.servlet.multipart.max-file-size) → 너무 큰 파일이 업로드되지 않도록 적절한 크기 제한을 설정해야 한다.
  • 업로드된 파일의 저장 위치 및 접근 제어 전략 → 업로드된 파일을 서버 내부에 저장하는 경우 접근 권한을 제한해야 한다.

정리

Spring Boot에서 multipart/form-data와 JSON을 함께 처리할 때는 @RequestPart를 사용해야 하며, Boolean 값을 @RequestPart로 받을 경우 String으로 변환한 후 처리하는 것이 안전하다.

Postman에서 데이터를 전송할 때는 반드시 Text 형식으로 보내야 하며, multipart/form-data를 사용할 경우 각 필드의 타입을 정확하게 지정하는 것이 중요하다.

profile
조금씩 매일 성장하자

0개의 댓글