/assets/img/2019-12-05_spring_cloud_feign_proxy-640.png

Spring Cloud: Use FeignClient behind a corporate proxy

tl;dr: This post shows how to implement a custom HttpClientFactory which is used by Spring Cloud / Feign to configure a proxy.

Contents

Note: This post is deprecated and it is recommended to use the httpclient-spring-boot-starter

Depending on the IT department, it can become complicated quickly and a different proxy server is required depending on the target server.

FeignClients are used in a Spring Boot project and are completely configured via annotations. In the background Feign then uses one of the available HttpClients for the requests, for example:

  • Apache HttpClient (default)
  • OkHttp (by the dependency io.github.openfeign:feign-okhttp)

In the spring-cloud-openfeign project there are already several configurations for the Http clients1, for example timeouts, SSL validation or number of connections. Unfortunately the possibility to configure one or more proxies is missing at this point.

The proxy must be configured in the used HttpClient (see Apache HttpClientBuilder2 and OkHttpClient Builder3).

Theoretically you can pass this Feign in the Builder, but then you lose the advantage that a FeignClient only consists of one interface4.

Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("my_proxy_url", 1234));
OkHttpClient okHttpClient = new OkHttpClient.Builder().proxy(proxy).build();
Feign.Builder builder = Feign.builder().client(new feign.okhttp.OkHttpClient(okHttpClient));
...

Custom HttpClientFactory

Therefore in my experience it is best to use a Custom HttpClientFactory and configure the proxy in it. This factory is then responsible for the generation of all HttpClients and the existing implementation of the FeignClients can remain.

The implementation of the factory is almost identical for both the Apache HttpClient and OkHttp, so here is just an example for OkHttp.

As a basis the class DefaultOkHttpClientFactory can be extended. Within the method public Builder createBuilder(boolean disableSslValidation) the actual configuration of the proxy takes place.

public class ProxyOkHttpClientFactory extends DefaultOkHttpClientFactory {

  // Constructor, imports and foo omitted for better readability

  @Override
  public Builder createBuilder(boolean disableSslValidation) {
    Builder builder = super.createBuilder(disableSslValidation);
    builder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("my_proxy_url", 1234)));
    return builder;
  }
}

Of course, the proxy URL and port should be configurable, so it makes sense to include them in the properties.

In case you need more than one proxy instead of just one, you can call .proxySelector(...) instead of .proxy(...) and pass an implementation of a ProxySelector. This then returns in the method public List<Proxy> select(URI uri) a list with a proxy matching a URL.

The final step is to make sure that our implementation is used instead of the default factory.

@Configuration
@EnableConfigurationProperties(HttpClientProperties.class)
public class HttpClientConfiguration {

  @Configuration
  @ConditionalOnProperty(name = "httpclientfactories.ok.enabled", matchIfMissing = true)
  @ConditionalOnClass(OkHttpClient.class)
  static class OkHttpClientConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public OkHttpClientFactory okHttpClientFactory(Builder builder, HttpClientProperties okHttpClientProperties) {
      return new ProxyOkHttpClientFactory(builder, okHttpClientProperties);
    }
  }
}

You’ll also need to add the following dependency:

<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-okhttp</artifactId>
</dependency>

and enable feign-okhttp in your configuration:

feign.okhttp.enabled=true

Footnotes

Tags

Comments

Related