Programming/SpringBoot

[Spring] Content-Type 'application/octet-stream' is not supported

owls 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