개발 기록

> [Spring] Spring 은 요청을 어떻게 처리 해주고 있는 걸까? (5) HttpMessageConvert 본문

DIVE

> [Spring] Spring 은 요청을 어떻게 처리 해주고 있는 걸까? (5) HttpMessageConvert

1z 2023. 12. 12. 11:23

 

 

 

1. Http Message Convert  개념  

Http Message Converter 를 사용하여 JSON 및 XML과 Java 개체를 마샬링 및 마샬링 해제 한다.
즉 JSON 데이터를 HTTP 메시지 바디에서 직접 읽거나 쓸 때 사용한다.

 

스프링은 다음의 경우에 HTTP 메시지 컨버터를 사용한다.
☞ HTTP 요청 -> @RequestBody, HttpEntity / RequestEntity
HTTP 응답 -> @ResponseBody, HttpEntity / ResponseEntity
  기본적인 문자는 StringHttpMessageConverter, 객체는 MappingJackson2HttpMessageConverter가 동작

 

(1) HttpMessageConverter method 알아보기

 

메서드명 설명
canRead(Class<?> clazz, MediaType mediaType) Converter 가 지정된 클래스를 읽을 수 있는지 여부
canRead(Class<?> clazz, MediaType mediaType) Converter 가 지정된 클래스를 작성할 수 있는지 여부
getSupportedMediaTypes() 지원하는 미디어 유형리턴.
read(Class<? extends T> clazz, HttpInputMessage inputMessage) 입력 메시지에서 주어진 유형의 객체를 읽고 반환.
write(T t, MediaType contentType, HttpOutputMessage outputMessage) 출력 메시지에서 주어진 객체 작성

 

 

(2) 동작원리 

▶ Http 요청이 들어왔을 때

1. @RequestBody or HttpEntity를 파라미터로 사용하고 있는 핸들러 메서드에 요청이 들어옴.

2. canRead()를 호출하여 대상 클래스 타입(Object 타입)을 지원하는지 확인한다.

3. Http 요청의 Content-type을 확인하여 해당 미디어 타입을 지원하는지 확인.

4. 통과했다면 read()를 통해서 객체 생성 및 반환 작업 진행

 

 Http 응답을 생성할 때

1. 핸들러 메서드에서 @ResponseBody나 HttpEntity로 값이 반환된다.

2. canWrite()를 호출하여 메시지를 쓸 수 있는지 확인한다.

3. 대상 클래스 타입을 지원하는지 확인한다.

4. Http 요청의 Accept을 확인하여 해당 미디어 타입을 지원하는지 확인. (혹은 @RequestMapping의 produces 부분 확인)

5. 통과했다면 write()를 통해서 HTTP 응답 메시지 바디에 데이터 생성

 

 2. Http Message Converter 수행처  

 

ArgumentResolver 가 핸들러 메서드의 인자값을 바인딩 할 때 Converter 를 사용한다.

 

@RequestBody 의 경우는 RequestResponseBodyMethodProcessor (ArgumentResolver) 에서 HttpEntity 경우에는 HttpEntityMethodProcessor (ArgumentResolver) 에서  HTTP 메시지 컨버터를 사용해서 필요한 객체를 생성한다!

 

아래는 RequestResponseBodyMethodProcessor 흐름만 작성했다.

 

 

(1) readWithMesageConverters 메서드

 

readWithMesaageConverters 메서드의 return 값인 Object 을 넘겨받는 것을 볼 수 있다.

 

이 Object 가 어떤 객체 인지 아래 코드를 확인해보자.

 

(2)  AbstractMessageConverterMethodArgumentResolver.readWithMesageConverters

 

HandlerMethodArgumentResolver 구현체 

- Http Message Converter 를 사용해서 핸들러 메서드에 필요한 객체를 생성해준다

@Nullable
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
...
    try {
....
            HttpMessageConverter converter;
            Class converterType;
            GenericHttpMessageConverter genericConverter;
            
            // 반복문을 통해 메시지 컨버터 반복문을 돈다.
            while(true) {
...
                converter = (HttpMessageConverter)var11.next();
                converterType = converter.getClass();
...
                genericConverter = var28;
                if (genericConverter != null) {
...
				// canRead()를 통해 해당 converter 가 데이터를 읽을수 있는지 검사한다.
                } else if (targetClass != null && converter.canRead(targetClass, contentType)) {
                   // 데이터를 읽을 수 있으면 반복문을 빠져나온다.
                   break;
                }
            }
...
            if (message.hasBody()) {
                HttpInputMessage msgToUse = this.getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
                
                // 해당 Convert 로 read 메서드로 데이터를 읽는다.
                body = genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) : converter.read(targetClass, msgToUse);
                body = this.getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
            } else {
                body = this.getAdvice().handleEmptyBody((Object)null, message, parameter, targetType, converterType);
            }
        }
...
}

 

 

※ HTTP 응답 생성 시

RequestResponseBodyMethodProcessor Class 의 handleReturnValue 메서드에서  messageConverter를 호출해서 응답 결과를 만듬

 

 

 3. Spring 에서 제공하는 Message Convert 유형  

 

1. ByteArrayHttpMessageConverter – 바이트 배열을 변환

- @RequestBody byte[] paramter

-  ex. 파일 업로드

- Response Media Type :  application/octet-stream

 

2. StringHttpMessageConverter – 문자열을 변환.

- @RequestBody String param

- Response content-type :  text/plain

 

3. FormHttpMessageConverter – 양식 데이터를 MultiValueMap<String, String> 으로/에서 변환

- @RequestBody MultiValueMap<String, String>

- Media Type : application/x-www-form-urlencoded

- Form-data 를 주고받을 때 사용한다.( @ModelAttribute 주로 사용)

 

4. MappingJacksonHttpMessageConverter – JSON을 변환

- Jackson의 ObjectMapper를 활용해서 Json과 오브젝트 사이의 변환을 지원해준다. 

- content-type: application/json

 

5. Jaxb2RootElementHttpMessageConverter – Java 객체를 XML로/에서 변환

6. MappingJackson2HttpMessageConverter – JSON을 변환

7. ResourceHttpMessageConverter – 모든 유형의 옥텟 스트림에 대해 org.springframework.core.io.Resource를 변환

8. SourceHttpMessageConverter – javax.xml.transform.Source를 변환

9. AtomFeedHttpMessageConverter – Atom 피드를 변환

10. RssChannelHttpMessageConverter – RSS 피드를 변환

 

 

 

 

 

 

 

 

 

 

참고

https://www.baeldung.com/spring-httpmessageconverter-rest

https://cl8d.tistory.com/11