【技术分享】一、 SpringCloud Fegin融合okhttp 踩坑记录(含跳过SSL证书验证)

【技术分享】一、 SpringCloud Fegin融合okhttp 踩坑记录(含跳过SSL证书验证)

踩坑bug

  1. clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on JDK 9+
  2. java.net.UnknownHostException: 找不到请求地址(consul)

1. 默认fegin通过https请求绕过SSL证书验证

使用默认fegin配置 跳过SSL证书校验

@Slf4j
@Configuration
public class FeignConfig {
    @Bean
    Logger.Level deviceSendCmdFeignLoggerLevel() {
        return Logger.Level.FULL;
    }

    @Bean
    @ConditionalOnMissingBean
    public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
                              SpringClientFactory clientFactory) throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext ctx = SSLContext.getInstance("SSL");
        X509TrustManager tm = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        ctx.init(null, new TrustManager[]{tm}, null);
        return new LoadBalancerFeignClient(new Client.Default(ctx.getSocketFactory(),
                new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                }),
                cachingFactory, clientFactory);
    }
}

pom文件。

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!-- 使用Apache HttpClient替换Feign原生httpclient -->
<dependency>
   <!--不是netfix包下了,应该是独立出来开源了-->
   <groupId>io.github.openfeign</groupId>
   <artifactId>feign-httpclient</artifactId>
   <version>9.4.0</version>
   <!-- <version>9.5.1</version> 这里可以不指定version spring-boot-parent中已经有版本定义-->
</dependency>   
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2. 将默认fegin调用方式改为Okhttp

  1. applicattion.yml配置
feign:
  httpclient: --- 关闭
    enabled: false
  okhttp:     --- 开启
    enabled: true
  hystrix:
    enabled: true
  1. pom文件
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>

3.确认OkhttpClient类型

  1. 到此为止
  2. 如果不需要配置跳过SSL证书验证 底层就已经切换为OkhttpClient调用方式了
    验证:SynchronousMethodHandler类中查看 请求request使用的fegin类型
   public Object invoke(Object[] argv) throws Throwable {
        RequestTemplate template = this.buildTemplateFromArgs.create(argv);
        Options options = this.findOptions(argv);
        Retryer retryer = this.retryer.clone();

        while(true) {
            try {
                return this.executeAndDecode(template, options);
            } catch (RetryableException var9) {...........}
        }
    }

    Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
        Request request = this.targetRequest(template);
        if (this.logLevel != Level.NONE) {
            this.logger.logRequest(this.metadata.configKey(), this.logLevel, request);
        }

        long start = System.nanoTime();

        Response response;
        try {
        
        	<!--看这  查看clent类型 -->
        	<!--看这  查看clent类型 -->
            response = this.client.execute(request, options);
            <!--看这  查看clent类型 -->
            <!--看这  查看clent类型 -->
            
            response = response.toBuilder().request(request).requestTemplate(template).build();
        } catch (IOException var13) {
            ..................
        }
    }

4.Okhttp配置跳过SSL证书踩坑!!!

  1. 使用步骤一中的方式直接注入OkhttpClient示例的方式走不通,Client.Default 没有对代码实现注入方法 即使注入代码不报错 服务还是调用不成功的
  2. 采用对 okhttp 直接配置的方式 注入 configuration
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
    @Bean
    public okhttp3.OkHttpClient okHttpClient(){

        okhttp3.OkHttpClient.Builder builder = new okhttp3.OkHttpClient.Builder();
        try {
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            builder.readTimeout(60, TimeUnit.SECONDS);
            builder.connectTimeout(60, TimeUnit.SECONDS);
            builder.sslSocketFactory(sslSocketFactory);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        builder.connectionPool(new ConnectionPool());
        return builder.build();
    }
}
  1. 到这你是不是以为问题解决了???? 不可能!!!还有个大坑 且听我娓娓道来

5.okhttp与jdk版本不兼容问题

错误【clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on JDK 9+】:
【技术分享】一、 SpringCloud Fegin融合okhttp 踩坑记录(含跳过SSL证书验证)

  1. 针对jdk 1.8.0_251、okhttp4.3.0以下版本不兼容问题
    详细过程分析 请看 链接: link.
  2. 解决方法1:调用sslSocketFactory时候传入trustManager。(推荐此做法,无论okhttp、okhttp版本是什么,都不会报错)。
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
    @Bean
    public okhttp3.OkHttpClient okHttpClient(){

        okhttp3.OkHttpClient.Builder builder = new okhttp3.OkHttpClient.Builder();
        try {
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            
			<!-- 区别在这 -->
			<!-- 区别在这 -->
            X509TrustManager trustAllCert = (X509TrustManager) trustAllCerts[0];
            builder.sslSocketFactory(sslSocketFactory,trustAllCert);
            <!-- 区别在这 -->
			<!-- 区别在这 -->

            builder.readTimeout(60, TimeUnit.SECONDS);
            builder.connectTimeout(60, TimeUnit.SECONDS);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        builder.connectionPool(new ConnectionPool());
        return builder.build();
    }
}
  1. 升级okhttp4.3.0以上版本或降级至jdk1.8.0_251之前版本。
上一篇:关于electron-vue打包后静态视频文件无法正常加载的问题解决方法


下一篇:理解ASP.NET Core - [04] Host