2019-10-31 spring Cloud 无法注册到nacos问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019-10-31 spring Cloud 无法注册到nacos问题相关的知识,希望对你有一定的参考价值。

参考技术A 最近在学习nacos的使用,按照官方文档写了一个SpringCloud+nacos的小demo,却发现注册进nacos注册中心,日志是这样的:

后来发现我springboot的版本是2.2.0.RELEASE

降低到 2.0.8.RELEASE后就能注册了,和nacos的官网说明:版本 0.2.x.RELEASE 对应的是 Spring Boot 2.x 版本,版本 0.1.x.RELEASE 对应的是 Spring Boot 1.x 版本有些偏差。

此处:nacos 1.1.4  、

pom.xml如下

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

        <version>2.0.8.RELEASE</version>

<relativePath/>

    </parent>

<groupId>com.candy</groupId>

<artifactId>nacos-remotecall</artifactId>

<version>0.0.1-SNAPSHOT</version>

<name>nacos-remotecall</name>

<description>Demo project for Spring Boot</description>

<properties>

<java.version>1.8</java.version>

<junit.version>4.10</junit.version>

<spring-cloud.version>Finchley.SR2</spring-cloud.version>

</properties>

<dependencies>

        <dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

        <dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>

<version>0.9.0.RELEASE</version>

</dependency>

        <dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-openfeign</artifactId>

<version>2.0.0.RELEASE</version>

</dependency>

        <dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

<exclusions>

<exclusion>

<groupId>org.junit.vintage</groupId>

<artifactId>junit-vintage-engine</artifactId>

</exclusion>

</exclusions>

</dependency>

        <dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>$junit.version</version>

<scope>test</scope>

</dependency>

</dependencies>

<dependencyManagement>

<dependencies>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-dependencies</artifactId>

<version>$spring-cloud.version</version>

<type>pom</type>

<scope>import</scope>

</dependency>

</dependencies>

</dependencyManagement>

<build>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

</plugin>

</plugins>

</build>

</project>

Spring Cloud项目中通过Feign进行内部服务调用发生401407错误无返回信息的问题

问题描述

最近在使用Spring Cloud改造现有服务的工作中,在内部服务的调用方式上选择了Feign组件,由于服务与服务之间有权限控制,发现通过Feign来进行调用时如果发生了401、407错误时,调用方不能够取回被调用方返回的错误信息。

产生原因

Feign默认使用java.net.HttpURLConnection进行通信,通过查看其子类sun.net.www.protocol.http.HttpURLConnection源码发现代码中在进行通信时单独对错误码为401\\407的错误请求做了处理,当请求的错误码为401\\407时,会关闭请求流,由于此时还并没有将返回的错误信息写入响应流中,所以接收的返回信息中仅仅能获取到response.status(),而response.body()null
HttpURLConnection相关信息的源码链接:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/net/www/protocol/http/HttpURLConnection.java#1079

解决思路

关于此问题产生的原因已经很明显了,就是feign.Client实现通信的方式选用了我们不想使用的HttpURLConnection。想到通常在Spring的代码中OCP都是运用得很好的,所以基本上有解决此问题的信心了,最不济就是自己扩展Feign,实现一个自己想要的feign.Client,当然这种事情Spring Cloud基本都会自己搞定,这也是Spring Cloud强大完善的一个地方。
通过这个思路查看源码,果然看到了Spring Cloud在使用Feign提前内置了三种通信方式(feign.Client.Defaultfeign.httpclient.ApacheHttpClientfeign.okhttp.OkHttpClient),其中缺省的情况使用的就是feign.Client.Default,这个就是使用HttpURLConnection通信的方式。

源码解析

Spring Cloud项目中使用了Ribbon的组件,其会帮助我们管理使用Feign,查看org.springframework.cloud.netflix.feign.ribbon.FeignRibbonClientAutoConfiguration源码

@ConditionalOnClass( ILoadBalancer.class, Feign.class )
@Configuration
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignRibbonClientAutoConfiguration 

    @Bean
    @ConditionalOnMissingBean
    public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
                SpringClientFactory clientFactory) 
        return new LoadBalancerFeignClient(new Client.Default(null, null), cachingFactory, clientFactory);
    

    @Configuration
    @ConditionalOnClass(ApacheHttpClient.class)
    @ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
    protected static class HttpClientFeignLoadBalancedConfiguration 

        @Autowired(required = false)
        private HttpClient httpClient;

        @Bean
        @ConditionalOnMissingBean(Client.class)
        public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
                    SpringClientFactory clientFactory) 
            ApacheHttpClient delegate;
            if (this.httpClient != null) 
                delegate = new ApacheHttpClient(this.httpClient);
            
            else 
                delegate = new ApacheHttpClient();
            
            return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
        


    @Configuration
    @ConditionalOnClass(OkHttpClient.class)
    @ConditionalOnProperty(value = "feign.okhttp.enabled", matchIfMissing = true)
    protected static class OkHttpFeignLoadBalancedConfiguration 

        @Autowired(required = false)
        private okhttp3.OkHttpClient okHttpClient;

        @Bean
        @ConditionalOnMissingBean(Client.class)
        public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
                    SpringClientFactory clientFactory) 
            OkHttpClient delegate;
            if (this.okHttpClient != null) 
                delegate = new OkHttpClient(this.okHttpClient);
            
            else 
                delegate = new OkHttpClient();
            
            return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
        
    

  • feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory) 方法结合其上注解我们可以很清楚的知道,当没有feign.ClientBean的时候会默认生成feign.Client.Default来进行通信,这就是之前说的缺省通信方式
  • HttpClientFeignLoadBalancedConfigurationOkHttpFeignLoadBalancedConfiguration,我们可以看到其生效的条件,当classpath中有feign.httpclient.ApacheHttpClient并且配置feign.httpclient.enabled=true(缺省为true)、feign.okhttp.OkHttpClient并且配置feign.okhttp.enabled=true(缺省为true)
  • 当使用ApacheHttpClient或者OkHttpClient进行通信时就不会导致发生401\\407错误时,取不到返回的错误信息了

解决方法

通过其上的分析,解决方法已经显而易见了,

  1. pom.xml文件中新增

      <dependency>
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign-okhttp</artifactId>
            <version>8.18.0</version>
      </dependency>

或者

      <dependency>
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign-httpclient</artifactId>
            <version>8.18.0</version>
      </dependency>
  1. application.properties文件中增加(可缺省,如有切换调用方式需求可添加配置进行控制)
    feign.okhttp.enabled=true
    或者
    feign.httpclient.enabled=true

总结

  • 由于新增的依赖没有被starter管理,并且缺省不会导致程序启动异常,并且返回响应为null与此依赖没有直接关系,因此不方便定位到问题,特此记录下来,希望能帮助到遇到同样问题的人,如对文章有不同的看法,望给予指正。
  • 本文建立在已经搭建完成Feign的调用基础之上,没有讲述Feign的使用,因为此类文章很多,在此就不重复了。



作者:vincent_ren
链接:https://www.jianshu.com/p/44e877e395a9
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

以上是关于2019-10-31 spring Cloud 无法注册到nacos问题的主要内容,如果未能解决你的问题,请参考以下文章

Dubbo 和 Spring Cloud 的区别?

Spring Cloud Zuul API 网关不会为无状态会话转发 JWT 令牌

Spring Cloud 与 Dubbo 区别

Spring Cloud 与 Dubbo 区别

spring cloud --- Ribbon 客户端负载均衡 + RestTemplate ---心得无熔断器

spring cloud --- Ribbon 客户端负载均衡 + RestTemplate ---心得无熔断器