HTTP 메시지 컨버터란?
JSON 데이터를 HTTP 메시지 바디에서 직접 읽거나 쓰는 경우, HTTP 메시지 컨버터를 사용하면 매우 편리하다!
HTTP 메시지 컨버터란, 요청 본문에서 메시지를 읽어들이거나(@RequestBody), 응답 본문에 메시지를 작성할 때(@ResponseBody) 사용하는 컨버터다.
🔻 포스팅을 보기 전, @ResponseBody를 다시 살펴보자.
- 웹 브라우저가 "localhost:8080/hello-api" 접근
- 서버를 거쳐 helloController 호출
- helloController의 @ResponseBody를 통해 HttpMessageConverter가 호출
- return 타입에 따라 JsonConverter 또는 StringConverter를 이용해 return
@ResponseBody의 사용
- HTTP의 Body에 문자 내용을 직접 반환
- viewResolver 대신 HttpMessageConverter 동작
- 기본 문자 처리: StringHttpMessageConverter
- 기본 객체 처리: MappingJacksonHttpMessageConverter
- 바이트 처리 등: HttpMessageConverter가 기본으로 등록
스프링 MVC가 HTTP 메시지 컨버터를 적용하는 경우
- 요청: @RequestBody, HttpEntity(RequestEntity) 사용
- 응답: @ResponseBody, HttpEntity(ResponseEntity) 사용
메시지 컨버터의 선택 기준
- 요청: HTTP Content-Type 헤더와 서버 컨트롤러의 파라미터 타입 정보 이용
- 응답: HTTP Accept 헤더와 서버 컨트롤러의 반환 타입 정보 이용
HTTP 메시지 컨버터 인터페이스
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
- HTTP 요청, 응답 양방향으로 사용
- canRead(), canWrite(): 메시지 컨버터가 해당 클래스, 미디어 타입을 지원하는지 체크
- read(), write(): 메시지 컨버터를 통해 메시지를 읽고 쓰는 기능
스프링 부트의 기본 메시지 컨버터
ByteArrayHttpMessageConverter StringHttpMessageConverter MappingJacksonHttpMessageConverter ... |
- 기본적으로 위의 컨버터들을 지원함
- 대상 클래스 타입과 미디어 타입을 체크해 사용여부 결정
(만족하지 않는 경우 다음 메시지 컨버터로 우선순위 넘어감) - ex1: @RequestBody String data 형식으로 요청이 오면 StringHttpMessageConverter 사용
- ex2: @ResponseBody return helloData로 쓰고 미디어 타입 application/json인 경우 MappingJacksonHttpMessageConverter 사용
HTTP 요청 데이터 읽기
- HTTP 요청이 들어오고, 컨트롤러에서 @RequestBody나 HttpEntity 파라미터 사용
- 메시지 컨버터가 canRead() 호출 // 읽을 수 있는 메시지인지 확인
- 대상 클래스 타입과 HTTP의 Content-Type 미디어 타입 지원하는지 - canRead() 만족 시 read() 호출해 객체 생성 및 반환
HTTP 응답 데이터 생성
- 컨트롤러에서 @ResponseBody나 HttpEntity로 값 반환
- 메시지 컨버터가 canWrite() 호출 // 메시지를 쓸 수 있는지 확인
- 대상 클래스 타입과 HTTP의 Accept 미디어 타입 지원하는지 - canWrite() 만족 시 write() 호출해 HTTP 응답 메시지 바디에 데이터 생성
HTTP 메시지 컨버터의 실행
그렇다면 이제 궁금한 것이 하나 생겼다. 🤔❓
HTTP 메시지 컨버터는 어디서 실행되는걸까?
SpringMvc 구조를 다시 보자
- HTTP 요청이 들어오면 핸들러 조회
- 핸들러를 처리할 수 있는 핸들러 어댑터 조회
- handle(handler)
- handler 호출
- ModelAndView 반환
- viewResolver 호출
- View 반환
- render(model) 호출
위 과정에서 4번 과정을 주목해보자.
어노테이션 기반의 핸들러(컨트롤러)의 여러 파라미터를 생성해서 호출할 수 있는 '핸들러 어댑터'
이 어댑터가 HTTP 메시지 컨버터와 관련이 있다.
먼저, @RequestMapping을 처리하는 핸들러 어댑터인 RequestMappingHandlerAdapter를 자세히 살펴보자.
- ArgumentResolver 호출
ArgumentResolver: 매우 다양한 종류의 파라미터를 유연하게 처리해 파라미터 값(객체) 생성 - 파라미터 값이 준비되면 컨트롤러를 호출하며 값을 넘겨줌
🔻 ArgumentResolver 코드 살펴보기
interface를 열어보면 아래와 같다.
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter);
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
supportsParameter()를 통해 해당 파라미터를 지원하는지 확인해보고,
resolveArgument()를 통해 파라미터(객체)를 생성해서 반환해준다.
이렇게 생성된 객체는 컨트롤러로 넘어가게 된다.
추가적으로 이 인터페이스를 확장하면 원하는 ArgumentResolver를 생성할 수도 있다.
그럼 이제 본격적으로 HTTP 메시지 컨버터는 어디있을까?
만약 ArgumentResolver에 요청하는 파라미터가 @RequestBody 또는 HttpEntity인 경우 HTTP 메시지 컨버터를 사용해 'read' 한다. 응답의 경우에도 @ResponseBody 또는 HttpEntity를 처리하는 ReturnValueHandler에서 HTTP 메시지 컨버터를 호출해 응답 결과를 'write' 한다.
본 게시글은 김영한 님의 '스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술' 강의를 구매 후 정리하기 위한 포스팅입니다.
내용을 임의로 추가, 수정, 삭제한 부분이 많으며 정확한 이해를 위해서 강의를 구매하시는 것을 추천 드립니다.
'Develop > Spring+JPA' 카테고리의 다른 글
Entity vs DTO vs VO (3) | 2021.11.23 |
---|---|
[Thymeleaf] 타임리프란? (+기본적인 사용법) (2) | 2021.10.15 |
[Spring] HTTP 응답 (0) | 2021.08.11 |
[Spring] http 요청 데이터 조회 (0) | 2021.08.09 |
[Spring] 헤더 조회 (0) | 2021.07.14 |