🌐 HttpMessageConverter란?
- HTTP 메시지 바디 ↔ 자바 객체/문자열/바이트 변환기
(ViewResolver대신 바디 직접 입출력할 때 동작)RequestBody/@ResponseBody등 바디 입출력 시ViewResolver대신 동작하며,
타입과 미디어 타입을 보고 적절한 컨버터가read()/write()를 수행함
🎯 왜 필요할까? (SSR vs CSR)
@Controller + View 템플릿 → 서버가 HTML 렌더링 (ViewResolver 경로)@RestController(+ @ResponseBody) → 서버가 데이터(JSON/TEXT/바이너리)를 메시지 바디에 직접 실어 보냄 (MessageConverter 경로)🕰️ 언제 동작할까?

@RequestBody, HttpEntity<>, RequestEntity<>@ResponseBody, ResponseEntity<>, @RestControllerHttpMessageConverter가 관여함🔍 내부 동작(선택 로직)
요청(Request) : canRead(파라미터 타입, 요청 Content-Type) == true ? read() : 다음 컨버터
응답(Response) : canWrite(반환 타입, 요청 Accept/produces) == true ? write() : 다음 컨버터
→ canRead(Class<?> clazz, @Nullable MediaType contentType)
→ canWrite(Class<?> clazz, @Nullable MediaType accept)
→ read(Class<? extends T> clazz, HttpInputMessage input)
→ write(T body, @Nullable MediaType contentType, HttpOutputMessage output)
consumes/produces를 컨트롤러에 명시하면406/415류 오류를 줄일 수 있음🧰 대표 컨버터 3개 & 우선순위
| 컨버터 | 대상 타입 | 주 미디어 타입 | 기본 응답(Content-Type) | 사용 예 |
|---|---|---|---|---|
🟦 ByteArrayHttpMessageConverter | byte[] | */* | application/octet-stream | 이미지/파일/바이너리 |
🟩 StringHttpMessageConverter | String | */* | text/plain | 단순 텍스트 |
🟧 MappingJackson2HttpMessageConverter | Object/Map | application/json | application/json | DTO ↔ JSON (Jackson 필요) |
→ 리스트 앞쪽일수록 우선됨
→ 커스터마이징 시 0번 인덱스로 추가하면 최우선
👨🍳 최소 예제 코드
// DTO 예시
@Data
@AllArgsConstructor @NoArgsConstructor
public class DataDto {
private String key;
}
@Slf4j
@RestController
@RequestMapping("/mc")
public class MessageConverterController {
// 1) byte[] <-> octet-stream
@PostMapping("/bytes")
public byte[] bytes(@RequestBody byte[] data) {
log.info("bytes");
return data; // 기본 응답: application/octet-stream
}
// 2) String <-> text/plain
@PostMapping(value = "/string", consumes = "text/plain", produces = "text/plain")
public String string(@RequestBody String data) {
log.info("string");
return data;
}
// 3) DTO <-> application/json
@PostMapping(value = "/json", consumes = "application/json", produces = "application/json")
public DataDto json(@RequestBody DataDto dto) {
log.info("json");
return dto;
}
}
🎬 Postman/cURL 시나리오
✅ 시나리오 A: JSON → String (성공)
요청 헤더: Content-Type: application/json
엔드포인트: POST /mc/string
(주의: consumes = text/plain인 경우 A는 415, B로 테스트 권장)
권장 테스트
POST /mc/json으로 DTO 왕복을 먼저 확인하고,
String 엔드포인트는 text/plain으로 테스트!
# String 엔드포인트(성공): text/plain
curl -X POST http://localhost:8080/mc/string \
-H "Content-Type: text/plain" \
-d "hello"
✅ 시나리오 B: JSON → DTO (성공)
curl -X POST http://localhost:8080/mc/json \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"key":"value"}'
# 기대: {"key":"value"} 와 함께 200 OK (또는 지정한 상태)
❌ 시나리오 C: text/plain → DTO (실패 예시)
Content-Type: text/plain@RequestBody DataDtocanRead가 없어 415 Unsupported Media Typecurl -X POST http://localhost:8080/mc/json \
-H "Content-Type: text/plain" \
-d '{"key":"value"}'
# 기대: 415 Unsupported Media Type
→ MappingJackson2HttpMessageConverter는 보통 application/json을 읽음
해결: Content-Type을 application/json으로 보내거나, 별도 컨버터/설정 준비
⚖️ 헤더 협상 핵심(Content-Type vs Accept)
Content-Type (ex. application/json, text/plain)Accept (ex. application/json)consumes/produces를 명시하면 매핑 단계에서 미리 거름String 반환 → text/plainObject 반환 → application/json (Jackson 컨버터가 등록되어 있을 때)🧭 오류 코드로 원인 역추적
| 상태 | 언제? | 전형적 원인 | 해결 방향 |
|---|---|---|---|
| 400 Bad Request | 파싱 시도했지만 실패 | JSON 문법 오류, DTO 타입 불일치, 빈 바디 | 요청 바디/DTO 검증, 로그 확인 |
| 415 Unsupported Media Type | 읽기 컨버터 없음 | Content-Type과 파라미터 타입 불일치 | 올바른 Content-Type, consumes 명시 |
| 406 Not Acceptable | 쓰기 컨버터 없음 | Accept와 반환 타입 불일치 | 올바른 Accept, produces 명시 |
| 500 Internal Server Error | 직렬화/구성 문제 | Jackson 의존성 누락, 순환참조, Lazy 로딩 | 의존성/모듈 추가, @JsonIgnore, DTO 분리 |
🧠 요약 정리
| 항목 | 요청(Request, @RequestBody) | 응답(Response, @ResponseBody) |
|---|---|---|
| 동작 시점 | 클라이언트 → 서버 (HTTP Body → 자바 객체) | 서버 → 클라이언트 (자바 객체 → HTTP Body) |
| 핵심 메서드 | canRead() → read() | canWrite() → write() |
| 판단 기준 | 파라미터 타입 + 요청 Content-Type | 반환 타입 + 요청 Accept / 컨트롤러 produces |
| 대표 컨버터 | ByteArrayHttpMessageConverter (byte[])StringHttpMessageConverter (String)MappingJackson2HttpMessageConverter (JSON → DTO) | 동일 컨버터로 역방향 적용 |
| 장점 | SQL·View 없이 데이터 직접 바인딩 가능 | 객체를 다양한 포맷(JSON, TEXT, BINARY)으로 쉽게 변환 |
| 단점 | Content-Type 불일치 시 415 오류 | Accept 불일치 시 406 오류 |
| 자주 발생 오류 | 400 (문법 오류/파싱 실패) 415 (지원 불가 미디어 타입) | 406 (Not Acceptable) 500 (직렬화 오류) |
| 보완 방법 | 컨트롤러에 consumes 지정DTO 검증 철저 | 컨트롤러에 produces 지정Jackson 모듈/DTO 분리 |
| 확장 포인트 | 커스텀 컨버터 등록 (extendMessageConverters) | 응답 포맷별 컨버터 우선순위 조정 |