Accept 란?
Accept
요청 HTTP 헤더는 MIME 타입으로 표현되는 클라이언트가 이해가 가능한 컨텐츠 타입이 무엇인지 알려줍니다. 참조링크(mdn)
즉, 클라이언트에서 Accept header에 타입을 서버에게 알려줌로써 서버에게 나 이러한 타입의 응답을 받을수 있어
라는 것을 알려줍니다.
그러면, Spring 같은 프레임워크에서는 Accept의 값에 의해서 적절한 응답에 대한 MessageConverter을 선택해서 전달해주지 않을까?라는 의문이 발생했고 코드로 따라가 보자.
Spring에서의 Accept 처리
1. RequestResponseBodyMethodProcessor.class -> handleReturnValue
RequestResponseBodyMethodProcessor.class
에서 handleReturnValue메서드
를 호출해서 Body값을 변환하게 되는데 이때 마지막에 AbstractMessageConverterMethodProcessor.writeWithMessageConverters를 통해서 적절한 응답값을 변환해준다.
2. AbstractMessageConverterMethodProcessor.writeWithMessageConverters에서
3. determineCompatibleMediaTypes메서드를 통해 Accept값을 비교해서 제공할 MediaType을 결정해 준다.
결과
이제 소스는 분석해 보았고 한번 실질적으로 요청을 보내보도록 하겠다.
사전 준비 코드 (Spring boot 3.2 기준)
- Controller
@RestController
public class AcceptController {
@GetMapping("/")
public VO echo() {
return new VO("Hello", "World");
}
}
- VO
public record VO(
String name,
String description) {
}
- gradle 의존성
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
//XML REST 서비스를 사용하기위해 사용
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
developmentOnly("org.springframework.boot:spring-boot-devtools")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
요청해보기
- Accept: application/xml로 지정
GET http://localhost:8080/ Accept: application/xml
- 결과
- Accept: application/json로 지정
GET http://localhost:8080/ Accept: application/json
- 결과
Accept는 여러 개의 타입을 정할 수 있는데 앞의 순서에 따라 기본적으로 우선순위를 지정한다.
GET http://localhost:8080/
Accept: application/xml, application/json
XML이 앞에 있음으로 XML이 응답으로 반환된다.
Accpet는 또한 q(1이 최대값)이라는 파라미터를 통해서 응답 우선순위를 결정할 수 있는데,
GET http://localhost:8080/
Accept: application/json;q=0.21, application/xml;q=1.0
다음과 같이 요청하면 xml의 우선순위 값이 큼으로 XML을 반환해 준다.
결론
Accpet에 따라 클라이언트의 요청값을 서버(Spring)에서 해석해서 적절한 응답값을 전달해 주는 것을 확인하였고
우선순위를 선정해서 전달하면 서버도 이에 맞게 전달해 주는 것도 확인을 하였다. 이때, 우선순위가 높은 순위여도
서버가 해당 MediaType을 지원하지 않고 후순위의 MediaType을 지원을 하게 되면 후순위의 응답으로 전달하는 것도 추가적으로 확인했었다.
Accpet에 대해서 별로 생각하지 않았었는데 별도 MediaType별로 새로운 API를 구현하는 게 아닌 단순 메시지 컨버터를 바꿈으로써 Spring에서 처리를 할 수 있음에 놀랐다.