이미지와 데이터 동시 처리 시 발생하는 Multipart 문제 해결

2025. 4. 29. 11:20·트러블슈팅

문제

진행 중인 프로젝트에서
이미지 파일(MultipartFile) 과 일반 데이터(JSON) 를 동시에 전송받는 API를 개발해야 했다.

하지만 다음과 같은 오류가 발생했다...

Resolved [org.springframework.web.bind.MissingServletRequestPartException: Required request part 'file' is not present]

/* 또는 */

Content type 'application/json' not supported

 

원인

Spring Boot에서는 요청을 처리할 때, 요청의 Content-Type에 따라 동작 방식이 달라진다.

  • @RequestBody 는 요청 전체가 application/json 타입일 때만 사용된다.
    즉, 파일과 JSON을 함께 받을 수 없다.
  • @RequestPart 는 요청이 multipart/form-data 타입일 때, 요청 파트별로 파일이나 JSON을 따로 처리할 수 있다.

해결

요청을 MediaType.MULTIPART_FORM_DATA_VALUE 로 설정하고, @RequestPart 를 사용

/* 예시 코드 */
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> upload(
    @RequestPart("file", required = false) MultipartFile file,
    @RequestPart("data") MyRequestDto data
) {
    // 파일(선택)과 JSON 데이터(필수)를 정상적으로 받음
    return ResponseEntity.ok("업로드 성공");
}

 

+ 추가 문제 발생

포스트맨으로 API 테스트를 할 경우, form-data 형식으로 Content-Type을 application/json 을 명시해준다면 정상적으로 동작합니다!!

 

하지만... Swagger에서는 "Content-Type 'application/octet-stream' is not supported"라고 예외가 발생합니다.

더보기

application/octet-stream은 MIME 타입 중 하나로, 알 수 없는 이진 파일을 의미합니다.
즉 전달하고자 하는 리소스의 유형이 명시되지 않아 인식할 수 없는 리소스인 경우에 해당 타입이 사용됩니다.

분명 swagger에서 분명히 multipart/form-data로 설정해서 보내고 있는데, 어째서 application/octet-stream 라는걸까.. 

확인 결과, 전체 Content-Type은 multipart/form-data이지만,
각 파트의 Content-Type은 null과 image/png였습니다.
이를 통해 파트 중 타입이 누락된 부분이 null로 들어가게 되면서 어떤 타입인지 알 수가 없어 타입이 octet-stream으로 처리되고 있었다는 것을 알 수 있었습니다.

따라서 이 문제를 해결하기 위해서는 application/octet-stream 타입을 처리할 수 있는 메시지 컨버터를 추가해야 합니다!

@Component
public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
    public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) {
        super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
    }

	// 해당 컨버터가 읽기 과정에서만 작동하도록 쓰기 과정은 false

    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return false;
    }

    @Override
    public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
        return false;
    }

    @Override
    protected boolean canWrite(MediaType mediaType) {
        return false;
    }
}

 

참고

https://seondays.tistory.com/79

저작자표시 비영리 변경금지 (새창열림)

'트러블슈팅' 카테고리의 다른 글

Unable to load io.netty.resolver.dns.macos 오류 해결 (Mac DNS 문제)  (0) 2025.04.24
Spring JPA Open-in-View 경고 해결  (0) 2025.04.24
Spring Data Redis: Repository store assignment 문제 해결  (0) 2025.04.24
'트러블슈팅' 카테고리의 다른 글
  • Unable to load io.netty.resolver.dns.macos 오류 해결 (Mac DNS 문제)
  • Spring JPA Open-in-View 경고 해결
  • Spring Data Redis: Repository store assignment 문제 해결
안녕 하리
안녕 하리
  • 안녕 하리
    보초 개발자
    안녕 하리
  • 전체
    오늘
    어제
    • 분류 전체보기 (13)
      • 트러블슈팅 (4)
      • Honey Tip! (5)
      • Language (3)
        • Java (0)
        • Kotlin (1)
        • SQL (2)
      • Cloud (0)
      • ETC (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
안녕 하리
이미지와 데이터 동시 처리 시 발생하는 Multipart 문제 해결
상단으로

티스토리툴바