Spring

[Spring] Restclient > proxy guide

curiousKidd 2025. 4. 24. 14:02
반응형

이번에 팀 프로젝트에서 외부 공공 API를 연동하면서 Spring 6에서 새롭게 도입된 RestClient를 사용해볼 일이 있었다.

기존에 쓰던 RestTemplate이나 WebClient랑 비교해도 꽤 직관적이고 깔끔해서 앞으로 메인으로 써볼 만하겠다는 생각이 들었는데, 프록시 환경에서 설정하는 과정에서 몇 가지 삽질이 있었다.

이 글에서는 RestClient의 기본 설정부터, 프록시(proxy) 환경에서 어떻게 세팅하는지에 대해 내가 겪은 내용과 함께 정리해본다.


RestClient에 대해 간단히 정리하면

Spring 6부터 등장한 RestClient는 기존의 RestTemplate보다 더 직관적이고 builder 기반으로 작성할 수 있는 HTTP 클라이언트다.

내부적으로는 HttpComponentsClientHttpRequestFactory나 JdkClientHttpRequestFactory 같은 다양한 구현체를 사용할 수 있고, WebClient처럼 비동기가 아닌 동기식 HTTP 호출을 위한 클라이언트다.

간단한 예는 이렇다

val restClient = RestClient.builder()
    .baseUrl("https://api.example.com")
    .build()

val result = restClient.get()
    .uri("/data")
    .retrieve()
    .body(String::class.java)

여기까진 직관적인데, 프록시 환경에서 호출이 필요할 때 설정이 꽤 중요하다.


프록시 설정은 구현체에 따라 다르다

RestClient의 프록시 설정은 내부에서 사용하는 ClientHttpRequestFactory 구현체에 따라 방식이 달라진다. 대표적으로 두 가지를 비교하면 다음과 같다

1. SimpleClientHttpRequestFactory

Spring이 기본적으로 제공하는 간단한 구현체다. 이 경우에는 직접 java.net.Proxy 객체를 주입할 수 있다.

val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("proxy.example.com", 8080))
val factory = SimpleClientHttpRequestFactory().apply {
    setProxy(proxy)
}

val restClient = RestClient.builder()
    .requestFactory(factory)
    .build()

이 방식은 아주 단순한 HTTP 프록시 환경에서는 간단하고 직관적으로 설정할 수 있다는 장점이 있다. 다만 Authenticator 설정이나 고급 설정은 어렵다.

2. JdkClientHttpRequestFactory

Java 11 이상의 HttpClient를 사용하는 구현체다. 이 방식은 프록시 설정을 ProxySelector를 통해 지정한다.

val proxySelector = ProxySelector.of(InetSocketAddress("proxy.example.com", 8080))
val httpClient = HttpClient.newBuilder()
    .proxy(proxySelector)
    .build()

val factory = JdkClientHttpRequestFactory(httpClient)
val restClient = RestClient.builder()
    .requestFactory(factory)
    .build()

이 방식은 더 세밀한 설정이 가능하고, 향후 프록시 인증이나 조건부 프록시 사용 등 확장성이 좋다.

요약하자면, 간단한 프록시만 필요하면 SimpleClientHttpRequestFactory를 쓰는 게 간편하지만, 인증이 필요한 프록시나 고급 제어가 필요한 경우에는 JdkClientHttpRequestFactory + HttpClient 조합이 더 적합하다.


프록시 인증이 필요하다면 Authenticator를 함께 설정해야 한다

ProxySelector는 인증 정보를 설정할 수 없기 때문에, 만약 프록시가 인증을 요구하는 환경이라면 반드시 Authenticator를 함께 설정해줘야 한다.

val authenticator = object : Authenticator() {
    override fun getPasswordAuthentication(): PasswordAuthentication {
        return PasswordAuthentication("user", "password".toCharArray())
    }
}

val httpClient = HttpClient.newBuilder()
    .proxy(proxySelector)
    .authenticator(authenticator)
    .build()

이렇게 하면 프록시 서버가 요구하는 기본 인증도 처리할 수 있다.


프록시 설정을 지원하는 공식 문서

Spring 공식 문서에서도 RestClient의 설정 관련 내용은 아래에서 확인할 수 있다


5년차 개발자로서 느낀 점

RestClient는 확실히 코드 가독성이 좋고, 설정도 간결해서 앞으로의 표준이 될 가능성이 크다.

하지만 프록시 환경에서는 여전히 HttpClient나 Java의 네트워크 API에 대한 이해가 어느 정도 필요하다.

특히, SimpleClientHttpRequestFactory와 JdkClientHttpRequestFactory 간의 차이점을 이해하지 못하면 디버깅에서 시간이 낭비되기 쉽다.

정리하자면, 단순한 설정에는 SimpleClientHttpRequestFactory, 인증이나 조건 분기 등 확장성이 필요하면 JdkClientHttpRequestFactory + HttpClient 조합을 쓰는 것이 좋다. 이 과정을 통해 구조를 한번 세팅해두면 테스트와 운영환경에서도 유연하게 구성할 수 있다. 앞으로 외부 API 연동이 많은 프로젝트라면 이 조합을 적극 고려해볼 만하다.

반응형