ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] Content-Type 'application/octet-stream' is not supported
    Programming/SpringBoot 2024. 5. 27. 15:01
    728x90

     

    컨트롤러에서 이미지 파일과 dto를 잘 받아오는지 확인하려는 메소드를 실행했을때 

        @LoginRequired
        @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
        public ResponseEntity<HttpStatus> test(@RequestPart(value = "files") List<MultipartFile> files, @RequestPart(value = "postDto") PostDto postDto, @LoginMember MemberDto memberDto){
    
            if(files.isEmpty()){
                return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
            }
    
            if(postDto == null || memberDto == null){
                return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
            }
    
            log.info(postDto.toString());
            log.info(memberDto.toString());
    
            return ResponseEntity.status(HttpStatus.OK).build();
        }

     

    Content-Type 'application/octet-stream' is not supported

    415 오류 메시지가 나왔다.

     

    application/octet-stream 타입은 뭘까?

    MIME

    Multipurpose Internet Mail Extensions

    음악이나 사진, 비디오 등의 이진 파일을 네트워크를 통해 전송할 목적으로 텍스트로 변환하고, 이를 수신하는 입장에서 다시 파일화할 때 사용해야 할 기준을 제시하기 위한 목적으로 사용된다.

     multipart/form-data 타입

    요청 바디에 담기는 내용의 종류가 하나가 아니라서 각 구성요소마다 따로 MIME타입을 지정해야하는 상황에서 사용한다.

     application/octect-stream 타입

    모든 이진 파일들의 제네릭한 타입을 의미

    -> 제네릭을 사용했다는 건 어떤 방법을 사용하여 텍스트를 해석해야할지 모를 때 사용하는 방법이다.

     

     

    Content-Type 'application/octet-stream' is not supported 오류 메시지는 

    application/octet-stream 형식으로 요청을 받았으며 서버측에서는 이 형식을 지원하지 않기 때문에 발생하는 예외라고 한다.

     

    컨트롤러에서 어노테이션으로 미디어 타입을 설정했는데 왜 application/octet-stream 으로 나올까??

     

    스프링에서 request를 받으면 메시지 컨버터를 통해 JSON->자바 객체로 변환해준다.

    HttpMessageConvert의 추상 구현체인 AbstractMessageConvertMethodArgumentResolver 를 통해 Http Request,Response를 자바 객체로 받을 수 있다.

    이 때, contentType의 값이 null인 경우 디폴트로 application/octet-stream타입으로 지정해버린다.

    이로 인해 서버측 예외 메시지에 해당 타입이 등장한 것이다.

     

     

     

    multipart/form-data -> application/octect-stream 변환 원인

    Http Request, Response를 자바 클래스로 만들어주는 HttpMessageConvert의 추상 구현체인 AbstractMessageConvertMethodArgumentResolve의 readWithMessageConverter메서드를 보면 contentType의 값이 null인 경우 디폴트로 application/octet-stream타입으로 지정해버린다. 이로 인해 서버 측 예외 메시지에는 해당 타입이 등장한 것이다.

     

    따라서 이 문제를 해결하기 위해 application/octet-stream 타입을 처리할 수 있는 메시지 컨버터를 Spring컨텍스트에 추가해야 한다.

     

     

    Custom converter생성

    @Component
    public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
    	
        //"Content-Type: multipart/form-data"헤더를 지원하는 HTTP요청 반환기
    	public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper){
            super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
        }
        
        /*
        기존 application/octet-stream 타입을 쓰기로 다루는 메시지 컨버터가 이미 존재 (ByteArrayHttpMessageConverter)
        따라서 해당 컨버터는 쓰기 작업에서 이용하면 안됨
         */
    
        @Override
        public boolean canWrite(Class<?> clazz, MediaType mediaType) {
            return false;
        }
    
        @Override
        public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
            return false;
        }
    
        @Override
        public boolean canWrite(MediaType mediaType){
            return false;
        }
    }

     

    ObjectMapper객체를 생성자로 받는다. 

    ObjectMapper는 JSON데이터와 Java객체 간의 변환을 담당하는 Spring의 기본 JSON라이브러리이다.

     

    커스텀 컨버터에서 HTTP응답 출력을 지원하지 않도록 canWrite()메서드들을 오버라이드하여 모두 false를 반환하도록 설정해야 한다. 따라서 이 메시지 컨버터는 주로 HTTP요청 데이터를 객체로 변환하는데 사용된다.

     

    AbstractJackson2HttpMessageConverter를 상속받는 이유는 Jackson라이브러리 기반으로 문자열 형태의 json을 클래스로 변환해줄 수 있는데, 현재 서버 측에서 문제가 되는 경우는 Multipart/form-data 이하의 application/json 타입이 누락되는 것이기 때문이다. 

     

    결국 문제를 해결하기 위해서는 application/octet-stream타입을 다루는 HttpMessageConvert를 추가하면 된다. 

    즉, application/octet-stream타입을 처리할 수 있는 메시지 컨버터를 Spring컨텍스트에 추가해야 한다.

    @Component어노테이션을 통해 빈으로 등록하면 Spring컨텍스트에서 이 클래스의 인스턴스가 생성되어 관리된다.

     

     

     

    참고

     

    https://velog.io/@zvyg1023/Spring-Boot-Swagger%EC%97%90%EC%84%9C-ReqeustPart%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-MultiPartFile%EA%B3%BC-DTO-%EC%B2%98%EB%A6%AC-%EC%8B%9C-Content-type-applicationoctet-stream-not-supported-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0

     

    https://tomining.tistory.com/190

     

    https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/json/MappingJackson2HttpMessageConverter.html

     

     

     

     

     

     

    728x90

    댓글

© 2022. code-space ALL RIGHTS RESERVED.