POST /ai/templates) Spring Boot에서 FastAPI에 템플릿 생성 요청을 보내는 기능을 구현하던 중 FastAPI에서 422 Unprocessable Entity 오류 발생
즉, FastAPI는 HTTP/1.1 요청을 기대하는데, Spring Boot RestClient가 HTTP/2로 요청을 보내서 FastAPI가 요청을 제대로 파싱하지 못한 것
🧐코드를 건들지도 않았는데 왜 갑자기 오류 발생했을까?
HttpComponentsClientHttpRequestFactory를 적용하니깐 왜 되는거지...?
Spring의 RestClient 내부를 보면 어떤 HTTP 클라이언트 팩토리를 사용할지 조건문으로 판단하는 코드를 확인할 수 있음

🤔 근데 조건문 안에 있는
httpComponentsClientPresent,jdkClientPresent와 같은 변수는 뭐지..?

DefaultRestClientBuilder의 클래스 초기화 블록 부분을 보면 클래스가 로딩될 때 의존성 존재 여부를 체크해서 boolean 변수에 저장함
httpComponentsClientPresent → Apache HttpClient 의존성이 존재 여부jdkClientPresent → JDK 내장 java.net.http.HttpClient 존재 여부즉, 의존성에 따라 내부적으로 사용하는 HTTP 클라이언트 팩토리가 바뀌는 것..
나는 JDK 11 이상을 사용해서
java.net.http.HttpClient가 기본 제공되기 때문에JdkClientHttpRequestFactory()가 선택된 것
🤔 그럼 왜 어떤건 되고 어떤건 안되는걸까? 기본 HTTP 버전을 살펴보자
public JdkClientHttpRequestFactory() {
this(HttpClient.newHttpClient());
}
✅ 아래를 보면 기본 설정으로 HTTP/2를 우선 사용한다고 명시됨
of {@linkplain HttpClient.Version#HTTP_2 HTTP/2}, a redirection policy of

public static CloseableHttpClient createSystem() {
return HttpClientBuilder.create().useSystemProperties().build();
}
HttpClientBuilder.build() 내부를 보면, 요청 실행을 담당하는 HttpRequestExecutor가 생성됨HttpRequestExecutor requestExecCopy = this.requestExec;
if (requestExecCopy == null) {
requestExecCopy = new HttpRequestExecutor();
}
HttpRequestExecutor는 기본 설정으로 Http1Config.DEFAULT를 사용하고 public static final Http1Config DEFAULT = (new Builder()).build();
Builder() {
this.version = HttpVersion.HTTP_1_1;
this.bufferSize = 8192;
this.chunkSizeHint = -1;
...
}
Http1Config.DEFAULT의 Builder 초기값을 보면 version = HttpVersion.HTTP_1_1로 되어있음✅ 결론: 별도 HTTP/2 설정이 없으면 Apache HttpClient는 HTTP/1.1을 기본으로 사용
사용한 코드 :
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;
@Configuration
public class RestClientConfig {
@Value("${rest.ai.base-url}")
private String baseUrl;
@Bean
public RestClient restClient() {
return RestClient.create(baseUrl);
}
}
httpclient5 의존성을 주석 처리하고 실행 → JDK HttpClient 사용 → HTTP/2 요청 → FastAPI 오류 발생


httpclient5 의존성 복원 → Apache HttpClient 사용 → HTTP/1.1 요청 → 정상 동작
