Configure Proxy Route Planner on Spring-Cloud-Feign
Asked Answered
S

4

6

Configure Proxy Route Planner on Feign

I need to know how to make requests being behind a proxy server using the spring boot REST client. I can do this configuration using apache commons for REST requests like this:

Method that performs POST:

Map <String, Object> map = new TreeMap <String, Object> ();

DynamicProxyRoutePlanner routePlanner = getProxy (param);

CloseableHttpClient closeableHttpClient = HttpClients.custom (). SetRoutePlanner (routePlanner) .build ();

GetProxy method:

private DynamicProxyRoutePlanner getProxy (Map <Integer, Object> param) {
        HttpHost proxy = new HttpHost ((String) param.get (PROXY), (Integer) param.get (PROXY_PORT));

        DynamicProxyRoutePlanner routePlanner = new DynamicProxyRoutePlanner (proxy);
        return routePlanner;
}

DynamicProxyRoutePlanner class:

public class DynamicProxyRoutePlanner implements HttpRoutePlanner {

    private DefaultProxyRoutePlanner defaultProxyRoutePlanner = null;

    public DynamicProxyRoutePlanner (HttpHost host) {
        defaultProxyRoutePlanner = new DefaultProxyRoutePlanner (host);
    }

    public void setProxy (HttpHost host) {
        defaultProxyRoutePlanner = new DefaultProxyRoutePlanner (host);
    }

    public HttpRoute determineRoute (HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
        return defaultProxyRoutePlanner.determineRoute (target, request, context);
    }
}

Summing up ...

  • I need to create this same ProxyRoutePlanner configuration on Feign.

EDITED --

I created a class

@Configuration
public class FeignConfiguration {

with the methods

@Bean
    @ConditionalOnMissingBean (CloseableHttpClient.class)
    public CloseableHttpClient httpClient () {
        DynamicProxyRoutePlanner routePlanner = getProxy ();
        CredentialsProvider credentialsProvider = getCredentials ();

        return HttpClients.custom ()
                .setDefaultCredentialsProvider (credentialsProvider)
                .setRoutePlanner (routePlanner) .build ();
    }

    private DynamicProxyRoutePlanner getProxy () {
        HttpHost proxy = new HttpHost (HOST_PROXY, PORT_PROXY);
        return new DynamicProxyRoutePlanner (proxy);
    }


    public CredentialsProvider getCredentials () {
        AuthCache authCache = new BasicAuthCache ();
        CredentialsProvider credsProvider = new BasicCredentialsProvider ();
        credsProvider.setCredentials (new AuthScope (HOST_PROXY, PORT_PROXY, AuthScope.ANY_HOST, "ntlm"),
                new NTCredentials (USER, PASS, "", DOMAIN));
        HttpClientContext context = HttpClientContext.create ();
        context.setCredentialsProvider (credsProvider);
        context.setAuthCache (authCache);
        return credsProvider;
    }

I have refitted the connection tests but even though Feign does not seem to be trying to use the proxy settings, see the error below:

2018-04-25 09: 59: 10.494 ERROR 25309 --- [nio-9063-exec-2] oaccC [. [. [.] [DispatcherServlet]: Servlet.service () for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.RetryableException: Connection refused (Connection refused) executing POST http://sinaflor-api.des.basis.com.br/api/empreendimentos] with root cause

java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect (Native Method) ~ [na: 1.8.0_171]
at java.net.AbstractPlainSocketImpl.doConnect (AbstractPlainSocketImpl.java:350) ~ [na: 1.8.0_171]
at java.net.AbstractPlainSocketImpl.connectToAddress (AbstractPlainSocketImpl.java:206) ~ [na: 1.8.0_171]
at java.net.AbstractPlainSocketImpl.connect (AbstractPlainSocketImpl.java:188) ~ [na: 1.8.0_171]
at java.net.SocksSocketImpl.connect (SocksSocketImpl.java:392) ~ [na: 1.8.0_171]
at java.net.Socket.connect (Socket.java:589) ~ [na: 1.8.0_171]
at sun.net.NetworkClient.doConnect (NetworkClient.java:175) ~ [na: 1.8.0_171]
at sun.net.www.http.HttpClient.openServer (HttpClient.java:463) ~ [na: 1.8.0_171]
at sun.net.www.http.HttpClient.openServer (HttpClient.java:558) ~ [na: 1.8.0_171]
at sun.net.www.http.HttpClient. <init> (HttpClient.java:242) ~ [na: 1.8.0_171]
at sun.net.www.http.HttpClient.New (HttpClient.java:339) ~ [na: 1.8.0_171]
at sun.net.www.http.HttpClient.New (HttpClient.java:357) ~ [na: 1.8.0_171]
at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient (HttpURLConnection.java:1220) ~ [na: 1.8.0_171]
at sun.net.www.protocol.http.HttpURLConnection.plainConnect0 (HttpURLConnection.java:1156) ~ [na: 1.8.0_171]
at sun.net.www.protocol.http.HttpURLConnection.plainConnect (HttpURLConnection.java:1050) ~ [na: 1.8.0_171]
at sun.net.www.protocol.http.HttpURLConnection.connect (HttpURLConnection.java:984) ~ [na: 1.8.0_171]
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0 (HttpURLConnection.java:1334) ~ [na: 1.8.0_171]
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream (HttpURLConnection.java:1309) ~ [na: 1.8.0_171]
at feign.Client $ Default.convertAndSend (Client.java:133) ~ [feign-core-9.3.1.jar: na]
at feign.Client $ Default.execute (Client.java:73) ~ [feign-core-9.3.1.jar: na]
at feign.SynchronousMethodHandler.executeAndDecode (SynchronousMethodHandler.java:97) ~ [feign-core-9.3.1.jar: na]
at feign.SynchronousMethodHandler.invoke (SynchronousMethodHandler.java:76) ~ [feign-core-9.3.1.jar: na]
at feign.ReflectiveFeign $ FeignInvocationHandler.invoke (ReflectiveFeign.java:103) ~ [feign-core-9.3.1.jar: na]
at com.sun.proxy $ Proxy112.send (Unknown Source) ~ [na: na]
Shu answered 23/4, 2018 at 13:50 Comment(0)
S
4

I was able to resolve the proxy configuration in feign using okHttpClient like this:

@Configuration
public class FeignConfigurationProxy {

    @Value("${url.proxy_host}")
    private String HOST_PROXY;
    @Value("${url.proxy_port}")
    private Integer PORT_PROXY;

    private OkHttpClient okHttpClient;
    private Proxy proxy;

    @PostConstruct
    public void init() {
        buildProxy();
        buildOkHttpClient();
    }

    @Bean(name = "feign")
    public Feign buildClient() {
        return Feign.builder().client(new feign.okhttp.OkHttpClient(okHttpClient)).build();
    }


    @Bean(name = "okhttpclient")
    public OkHttpClient okHttpClient() {
        return okHttpClient;
    }

    public void buildOkHttpClient() {
        buildProxy();
        okHttpClient = new OkHttpClient.Builder().proxy(proxy).build();
    }

    public void buildProxy() {
        proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(HOST_PROXY, PORT_PROXY));
    }

}

in pom.xml I added the dependencies:

<dependency>
<groupId> io.github.openfeign </ groupId>
<artifactId> feign-okhttp </ artifactId>
<version> 9.5.0 </ version>
</ dependency>
<dependency>
<groupId> com.squareup.okhttp3 </ groupId>
<artifactId> okhttp </ artifactId>
<version> 3.10.0 </ version>
</ dependency>
Shu answered 26/4, 2018 at 13:16 Comment(3)
Does the feign-okhttp perform better than the apache one? What are the performance configuration best practices?Martellato
maybe the same performance, using spring-cloud-feign, by default it uses the okhttp client instead of the apache client, which makes me think that okhttp actually has an advantage over the apache client! When it comes to setting up the http client, I believe that the best way to configure it is the default, by customizing the minimum possible, since it has already been designed in a way that will behave quickly and steadily for most cases, leaving the customizations for cases like this one where I had to actually handle requests through corporate proxy or not.Kohl
@DiegoCândidodaSilva - The spring cloud openfeign default is not OkHttpClient. It's instead feign.Client.Default. The OkHttpClient and ApacheHttpClient feign clients can be used by setting feign.okhttp.enabled or feign.httpclient.enabled to true, respectively, and having them on the classpath. Reference: cloud.spring.io/spring-cloud-openfeign/reference/html/…Thuythuya
T
5

With Spring cloud openfeign supporting three underlying implementations:

  1. Default
  2. ApacheHttpClient
  3. OkHttpClient

Depending on what implementation is used in your project, here is how you configure the feign client to use HTTP proxy: TRICK: You configure the feign client and then override the default client bean in the Spring application context.

With Default:

import feign.Client;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.InetSocketAddress;
import java.net.Proxy;

@Configuration
public class FeignConfiguration {
  ...
  @Bean
  public Client feignClient() {
      return new Client.Proxied(null, null, 
                 new Proxy(Proxy.Type.HTTP,
                     new InetSocketAddress(proxyHost, proxyPort)));
  }
}

With ApacheHttpClient:

when you have feign.httpclient.enabled: true in application.yml and below in your pom.xml or build.gradle:

pom.xml
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

build.gradle
implementation 'io.github.openfeign:feign-httpclient'


import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.http.HttpHost;

@Configuration
public class FeignConfiguration {
  ...
  @Bean
  public CloseableHttpClient feignClient() {
    return HttpClientBuilder.create().setProxy(
              new HttpHost(proxyHost, proxyPort)).build();
  }
}

With OkHttpClient:

when you have feign.okhttp.enabled: true in application.yml and below in your pom.xml or build.gradle:

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

build.gradle
implementation 'io.github.openfeign:feign-okhttp'


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.InetSocketAddress;
import java.net.Proxy;
import okhttp3.OkHttpClient;

@Configuration
public class FeignConfiguration {
  ...
  @Bean
  public OkHttpClient okHttpClient() {
    return new OkHttpClient.Builder()
       .proxy(new Proxy(Proxy.Type.HTTP, 
             new InetSocketAddress(proxyHost, proxyPort)))
       .build();
  }
}
Thuythuya answered 12/3, 2021 at 5:52 Comment(0)
S
4

I was able to resolve the proxy configuration in feign using okHttpClient like this:

@Configuration
public class FeignConfigurationProxy {

    @Value("${url.proxy_host}")
    private String HOST_PROXY;
    @Value("${url.proxy_port}")
    private Integer PORT_PROXY;

    private OkHttpClient okHttpClient;
    private Proxy proxy;

    @PostConstruct
    public void init() {
        buildProxy();
        buildOkHttpClient();
    }

    @Bean(name = "feign")
    public Feign buildClient() {
        return Feign.builder().client(new feign.okhttp.OkHttpClient(okHttpClient)).build();
    }


    @Bean(name = "okhttpclient")
    public OkHttpClient okHttpClient() {
        return okHttpClient;
    }

    public void buildOkHttpClient() {
        buildProxy();
        okHttpClient = new OkHttpClient.Builder().proxy(proxy).build();
    }

    public void buildProxy() {
        proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(HOST_PROXY, PORT_PROXY));
    }

}

in pom.xml I added the dependencies:

<dependency>
<groupId> io.github.openfeign </ groupId>
<artifactId> feign-okhttp </ artifactId>
<version> 9.5.0 </ version>
</ dependency>
<dependency>
<groupId> com.squareup.okhttp3 </ groupId>
<artifactId> okhttp </ artifactId>
<version> 3.10.0 </ version>
</ dependency>
Shu answered 26/4, 2018 at 13:16 Comment(3)
Does the feign-okhttp perform better than the apache one? What are the performance configuration best practices?Martellato
maybe the same performance, using spring-cloud-feign, by default it uses the okhttp client instead of the apache client, which makes me think that okhttp actually has an advantage over the apache client! When it comes to setting up the http client, I believe that the best way to configure it is the default, by customizing the minimum possible, since it has already been designed in a way that will behave quickly and steadily for most cases, leaving the customizations for cases like this one where I had to actually handle requests through corporate proxy or not.Kohl
@DiegoCândidodaSilva - The spring cloud openfeign default is not OkHttpClient. It's instead feign.Client.Default. The OkHttpClient and ApacheHttpClient feign clients can be used by setting feign.okhttp.enabled or feign.httpclient.enabled to true, respectively, and having them on the classpath. Reference: cloud.spring.io/spring-cloud-openfeign/reference/html/…Thuythuya
W
0

Just define your CloseableHttpClient as Spring Bean.

From Spring Cloud Edgware release, if you define CloseableHttpClient as Spring Bean, it will be used instead of default one.

Wield answered 24/4, 2018 at 10:24 Comment(4)
Do you have any examples of this configuration, how would you use feign?Kohl
No special configuration is required. Currrent FeignAutoConfiguration class only load its own CloseableHttpClient bean if not exist like following. @ConditionalOnMissingBean(CloseableHttpClient.class). So if you define your CloseableHttpClient as spean, it will be used inside feign.Wield
I edited the topic with the new errors after the suggested implementation, if you can help me with this solution will help me a lot.Kohl
which version of spring cloud are you using? And you don't need to use @ConditionalOnMissingBean for you.Wield
H
0

Working for my case using proxy to tunneling to another url

    public feign.Client feignClient() {
        OkHttpClient okHttpClient;
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, Integer.parseInt(proxyPort)));
        okHttpClient = new OkHttpClient.Builder()
                .proxy(proxy)
                .proxyAuthenticator(authenticator())
                .build();
        return new feign.okhttp.OkHttpClient(okHttpClient);
    }

    private okhttp3.Authenticator authenticator() {
        return (route, response) -> {
            String credential = okhttp3.Credentials.basic(proxyUser, proxyPassword);
            return response.request()
                    .newBuilder()
                    .header("Proxy-Authorization", credential)
                    .build();
        };
    }
Houppelande answered 19/7, 2024 at 15:28 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.