最近在项目中使用FeignClient发https(s)请求的时候发现一个非常奇怪的问题,在
上一个文章
我写了将项目中的OkHttpClient替换成FeignClient,这样能使的代码好看,易于维护。但是在替换的过程中发现,有一小部分替换之后发不了请求,使用OkHttpClient时可以返回正常的数据,但是使用FeignClient时则提示403,具体的信息如下:
这个是FeignClient的日志:
这个是错误信息:
为了检查是否由于Cookie或者request header的问题导致的,使用curl命令请求,如下:
上半部分是curl命令,可以发现我只携带了一个请求头「authorization」,其他什么都没有设置了,也是可以获得正确的返回值。
由于返回的信息部分属于公司财产,所以打码比较多,见谅
然后在debug的时候,发现FeignClient使用的是默认的客户端「
feign.client.Default
」,我就想切换成「OkHttpClient」,按照网上的教程
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
2. 修改配置文件
feign:
httpclient:
enabled: true
完成上述配置之后重新测试,还是使用的「feign.client.Default
」,默认的客户端。
之后查看FeignClientAutoConfiguration类,部分如下:
也就说在配置了{feign.okhttp.enabled=true}时,还需要判断当前容器中是否含有OkHttpClient类的对象,如果没有,则启动配置类;如果有,则配置类不生效。
所以,既然配置类不生效,那么最简单暴力的方式就是将「OkHttpFeignConfiguration」里面的信息都拷贝出来,然后自定义一个配置类。
完整的配置类代码如下:
import feign.Client;
import feign.Feign;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.commons.httpclient.OkHttpClientConnectionPoolFactory;
import org.springframework.cloud.commons.httpclient.OkHttpClientFactory;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.cloud.openfeign.support.FeignHttpClientProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
@Bean
@ConditionalOnMissingBean({Client.class})
public Client feignClient(okhttp3.OkHttpClient client) {
return new feign.okhttp.OkHttpClient(client);
@Bean
@ConditionalOnMissingBean({ConnectionPool.class})
public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties, OkHttpClientConnectionPoolFactory connectionPoolFactory) {
Integer maxTotalConnections = httpClientProperties.getMaxConnections();
Long timeToLive = httpClientProperties.getTimeToLive();
TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
@Bean
public OkHttpClient client(OkHttpClientFactory httpClientFactory, ConnectionPool connectionPool, FeignHttpClientProperties httpClientProperties) {
Boolean followRedirects = httpClientProperties.isFollowRedirects();
Integer connectTimeout = httpClientProperties.getConnectionTimeout();
Boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
return httpClientFactory.createBuilder(disableSslValidation)
.connectTimeout((long)connectTimeout, TimeUnit.SECONDS)
.followRedirects(followRedirects)
.connectionPool(connectionPool)
.build();
重启之后再次测试,成功解决问题。