FeignClient出现403错误,但是使用OkHttpClient或者curl请求没有问题。具体报错为「status 403 reading xxxxx#xxxx(), feign.FeignException$Forbidden: status 403 reading......」

最近在项目中使用FeignClient发https(s)请求的时候发现一个非常奇怪的问题,在上一个文章我写了将项目中的OkHttpClient替换成FeignClient,这样能使的代码好看,易于维护。但是在替换的过程中发现,有一小部分替换之后发不了请求,使用OkHttpClient时可以返回正常的数据,但是使用FeignClient时则提示403,具体的信息如下:

这个是FeignClient的日志:

 这个是错误信息:

为了检查是否由于Cookie或者request header的问题导致的,使用curl命令请求,如下:

上半部分是curl命令,可以发现我只携带了一个请求头「authorization」,其他什么都没有设置了,也是可以获得正确的返回值。由于返回的信息部分属于公司财产,所以打码比较多,见谅

然后在debug的时候,发现FeignClient使用的是默认的客户端「feign.client.Default」,我就想切换成「OkHttpClient」,按照网上的教程

  1. 导入依赖
<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();
    }
}

 重启之后再次测试,成功解决问题。

 

posted @ 2020-10-22 12:27  HMingR  阅读(9275)  评论(0编辑  收藏  举报