【问题标题】:Configure Proxy Route Planner on Spring-Cloud-Feign在 Spring-Cloud-Feign 上配置代理路由规划器
【发布时间】:2018-10-03 14:29:39
【问题描述】:

在 Feign 上配置代理路由规划器

我需要知道如何使用 Spring Boot REST 客户端在代理服务器后面发出请求。我可以使用 apache commons 对 REST 请求进行此配置,如下所示:

执行 POST 的方法:

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

DynamicProxyRoutePlanner routePlanner = getProxy (param);

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

GetProxy 方法:

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 类:

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);
    }
}

总结...

  • 我需要在 Feign 上创建同样的 ProxyRoutePlanner 配置。

已编辑--

我创建了一个类

@Configuration
public class FeignConfiguration {

方法

@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;
    }

我已经重新安装了连接测试,但即使 Feign 似乎没有尝试使用代理设置,请参阅以下错误:

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]

【问题讨论】:

    标签: rest configure http-proxy spring-cloud-feign feign


    【解决方案1】:

    Spring cloud openfeign 支持三种底层实现:

    1. 默认
    2. ApacheHttpClient
    3. OkHttpClient

    根据项目中使用的实现,以下是配置 feign 客户端以使用 HTTP 代理的方式: 技巧:您配置 feign 客户端,然后在 Spring 应用程序上下文中覆盖默认客户端 bean。

    默认:

    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)));
      }
    }
    

    使用 ApacheHttpClient:

    当您的application.yml 和以下pom.xmlbuild.gradle 中有feign.httpclient.enabled: true 时:

    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();
      }
    }
    

    使用 OkHttpClient:

    当您的application.yml 和以下pom.xmlbuild.gradle 中有feign.okhttp.enabled: true 时:

    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();
      }
    }
    

    【讨论】:

      【解决方案2】:

      我能够像这样使用 okHttpClient 在 feign 中解析代理配置:

      @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));
          }
      
      }
      

      在 pom.xml 中我添加了依赖项:

      <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>
      

      【讨论】:

      • feign-okhttp 的性能是否优于 apache?性能配置最佳做法是什么?
      • 可能性能一样,使用spring-cloud-feign,默认使用okhttp客户端而不是apache客户端,这让我觉得okhttp其实比apache客户端有优势!在设置 http 客户端时,我认为配置它的最佳方式是默认设置,即尽可能自定义最小值,因为它的设计方式在大多数情况下都可以快速稳定地运行,而无需针对这种情况的自定义,我必须通过公司代理实际处理请求。
      • @DiegoCândidodaSilva - spring cloud openfeign 默认不是 OkHttpClient。而是 feign.Client.Default。 OkHttpClientApacheHttpClient feign 客户端可以通过将 feign.okhttp.enabledfeign.httpclient.enabled 分别设置为 true 并将它们放在类路径中来使用。参考:cloud.spring.io/spring-cloud-openfeign/reference/html/…
      【解决方案3】:

      只需将您的 CloseableHttpClient 定义为 Spring Bean。

      从 Spring Cloud Edgware 版本开始,如果您将 CloseableHttpClient 定义为 Spring Bean,它将被使用而不是默认的。

      【讨论】:

      • 你有这个配置的例子,你会怎么用feign?
      • 不需要特殊配置。当前的 FeignAutoConfiguration 类仅在不存在时加载其自己的 CloseableHttpClient bean,如下所示。 @ConditionalOnMissingBean(CloseableHttpClient.class)。因此,如果您将 CloseableHttpClient 定义为 spean,它将在 feign 中使用。
      • 我在建议的实施后编辑了带有新错误的主题,如果您能帮助我解决这个问题,将对我有很大帮助。
      • 你用的是哪个版本的spring cloud?而且你不需要为你使用@ConditionalOnMissingBean。
      猜你喜欢
      • 2017-07-28
      • 2016-06-05
      • 2017-10-07
      • 2018-06-14
      • 2015-10-21
      • 2021-06-12
      • 2016-06-25
      • 2018-04-01
      • 1970-01-01
      相关资源
      最近更新 更多