将OkHttp自定义拦截器添加到Feign客户端

时间:2018-08-13 15:17:31

标签: java rest spring-cloud spring-cloud-feign feign

我在为OkHttp bean设置全局@FeignClient拦截器时遇到问题。我没有遇到任何错误,但是拦截器被忽略了。

我的理解是Spring Cloud的自动配置应该选择我声明的OkHttpClient.Builder bean,并使用它来创建基础的OkHttpClient实例,但是我对此可能是错的。

以下是我的Spring应用程序的相关部分:

@SpringBootApplication
@EnableFeignClients(defaultConfiguration = FeignConfig.class)    
@EnableCircuitBreaker
public class MyApp {

    public static void main(String[] args) {
        SpringApplication.run(GeoSigoStarter.class);
    }
}

@Configuration
public class FeignConfig {

    @Bean
    public MyInterceptor myInterceptor() {
        return new MyInterceptor();
    }

    @Bean
    public OkHttpClient.Builder okHttpClientBuilder(MyInterceptor interceptor) {
        return new OkHttpClient.Builder().addInterceptor(interceptor);
    }
}

public class MyInterceptor implements okhttp3.Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {

        Request request = chain.request();

        System.out.println("Hey there, this is my request: " + request);

        Response response = chain.proceed(request);

        System.out.println("Hey there, this is my response: " + response);

        return response;
    }

}

从不调用以上intercept方法。我需要MyInterceptor才能成为Spring bean,因为我需要向其注入其他依赖项。


@FeignClient(name = "myClient", fallback = MyClientFallback.class)
public interface MyClient {

    // method declarations
}

@Component
public class MyClientFallback implements MyClient {

    // method fallback implementations
}

这是我的application.properties文件的相关部分:

feign.hystrix.enabled = true
feign.okhttp.enabled = true

ribbon.eureka.enabled = false
ribbon.eager-load.enabled = true
ribbon.eager-load.clients = myClient

myClient.ribbon.listOfServers = <IP_LIST>
myClient.ribbon.ServerListRefreshInterval = 10000

从上面声明的属性中可以看到,我没有使用Eureka,而是使用Ribbon来平衡其余客户端的负载。我还使用Hystrix启用后备响应,并将feign.okhttp.enabled属性设置为true


以下是有关dependecies配置和版本的信息...

Spring Boot版本为2.0.3.RELEASE,Spring Cloud版本为Finchley.SR1,而OkHttp版本为3.11.0

在我的pom.xml文件中,我有以下spring-cloud-dependencies配置:

<dependencyManagement>
    <dependencies>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        ...

    </dependencies>
</dependencyManagement>

我还包括以下Spring Boot和Spring Cloud依赖项以及OkHttp依赖项:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.3.RELEASE</version>
</parent>

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>

    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>3.11.0</version>
    </dependency>

    ...

</dependencies>

3 个答案:

答案 0 :(得分:2)

您应将OkHttpClient bean作为stated in the doc

  

可以通过将feign.okhttp.enabled或feign.httpclient.enabled分别设置为true并将它们放在类路径中来使用OkHttpClient和ApacheHttpClient feign客户端。您可以通过提供使用Apache时的ClosableHttpClient Bean或使用OK HTTP的OkHttpClient来定制HTTP客户端。

https://github.com/OpenFeign/feign/blob/master/okhttp/src/main/java/feign/okhttp/OkHttpClient.java

答案 1 :(得分:1)

解决方案是让Spring自动配置完成其工作。

为此,必须从pom.xml文件中删除以下依赖项:

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.11.0</version>
</dependency>

并且必须手动添加以下内容:

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

完成此操作后,所提供的配置将按预期完成所有操作。

答案 2 :(得分:0)

解决方案是使用 OkHttpClient。添加 pom.xml 依赖:

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

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

并配置一个bean:

@Configuration
public class FeignConfiguration {

  @Bean
  public OkHttpClient client() {
    return new OkHttpClient();
  }
}

说明:对于 401、407 和其他一些 HTTP 状态响应,默认情况下 Open Feign 中使用的 HTTP 客户端会将正文替换为 null

From OpenFeign:目前在 feign.Default 客户端中启用了流模式。您可以在 sun.net.www.protocol.http.HttpURLConnection 中看到以下代码行:

if (respCode == HTTP_UNAUTHORIZED) { 
  if (streaming()) { 
    disconnectInternal(); 
    throw new HttpRetryException (RETRY_MSG2, HTTP_UNAUTHORIZED); 
  }
}

因此,如果启用了流式传输并且您有 401 HTTP 响应代码,您将获得空的 errorStream,因为没有初始化。 feign 客户端会尝试获取 errorStream 作为主体,因为有一个检查

if (status >= 400) { 
  stream = connection.getErrorStream(); 
} else { stream = connection.getInputStream(); }