Spring Cloud Gateway 采用 OpenFeign 远程调用失败的解决方案

文章目录

        • 一、框架版本
        • 二、源码展示
        • 三、问题描述
        • 四、解决方案

一、框架版本

  • Spring Boot、 Spring Cloud 、 Spring Cloud Alibaba

    框架名称 框架版本
    Spring Boot 2.2.5.RELEASE
    Spring Cloud Hoxton.SR3
    Spring Cloud Alibaba 2.2.1.RELEASE

二、源码展示

  • 远程鉴权 Controller 控制器代码片段

    @RestController
    @Slf4j
    @RequestMapping("/security")
    public class AuthenticationController {
           
    
        @Resource
        private AuthenticationService authenticationService;
    
        @PostMapping("/auth")
        public Boolean checkAuth(@RequestBody @Valid BaseRequest baseRequest) {
           
            log.info("<-------------------------->");
            return authenticationService.checkAuth(baseRequest);
        }
    }
    
  • 网关引用 OpenFeign 依赖

    
    
        org.springframework.cloud
        spring-cloud-starter-openfeign
        2.2.2.RELEASE
    
    
  • 网关 OpenFeign 调用客户端

    @Component
    @FeignClient(value = "rms-security-service")
    public interface InvokeSecurityServiceClient {
           
    
        @PostMapping("/security/auth")
        Boolean checkAuth(BaseRequest baseRequest);
    }
    

三、问题描述

  在网关层进行统一鉴权和认证的过程中,需要远程调用鉴权服务器的接口进行鉴权的操作。但是在采用 OpenFiegn 进行远程调用的过程中,出现了如下的报错堆栈,导致了远程调用失败

  • 堆栈信息

    feign.codec.EncodeException: No qualifying bean of type 'org.springframework.boot.autoconfigure.http.HttpMessageConverters' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {
           @org.springframework.beans.factory.annotation.Autowired(required=true)}
    	at feign.ReflectiveFeign$BuildEncodedTemplateFromArgs.resolve(ReflectiveFeign.java:384)
    	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
    Error has been observed at the following site(s):
    	|_ checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain]
    	|_ checkpoint ⇢ org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter [DefaultWebFilterChain]
    	|_ checkpoint ⇢ org.springframework.security.web.server.authentication.logout.LogoutWebFilter [DefaultWebFilterChain]
    	|_ checkpoint ⇢ org.springframework.security.web.server.savedrequest.ServerRequestCacheWebFilter [DefaultWebFilterChain]
    	|_ checkpoint ⇢ org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain]
    	|_ checkpoint ⇢ org.springframework.security.web.server.authentication.AuthenticationWebFilter [DefaultWebFilterChain]
    	|_ checkpoint ⇢ org.springframework.security.web.server.context.ReactorContextWebFilter [DefaultWebFilterChain]
    	|_ checkpoint ⇢ cn.com.jstec.open.cloud.gateway.config.SecurityConfig$$Lambda$772/0x0000016c006c3040 [DefaultWebFilterChain]
    	|_ checkpoint ⇢ org.springframework.security.web.server.header.HttpHeaderWriterWebFilter [DefaultWebFilterChain]
    	|_ checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
    	|_ checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
    	|_ checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
    	|_ checkpoint ⇢ HTTP GET "/open-platform/achievement/list?page=1" [ExceptionHandlingWebHandler]
    Stack trace:
    
  • 关键信息

    No qualifying bean of type 'org.springframework.boot.autoconfigure.http.HttpMessageConverters
    

四、解决方案

  • 堆栈分析

    HttpMessageConverters 没有被注入到容器中管理

  • ISSUES 跟踪

    点击此处 查看 issues 信息

  • 解决方案

    1. 源码:HttpMessageConverters.java 中没有发现异常,于是开始查看是否存在 AutoConfiguration 打开 HttpMessageConvertersAutoConfiguration.java

      @Configuration(proxyBeanMethods = false)
      @ConditionalOnClass(HttpMessageConverter.class)
      @Conditional(NotReactiveWebApplicationCondition.class)
      @AutoConfigureAfter({
                GsonAutoConfiguration.class, JacksonAutoConfiguration.class, JsonbAutoConfiguration.class })
      @Import({
                JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class,
      		JsonbHttpMessageConvertersConfiguration.class })
      public class HttpMessageConvertersAutoConfiguration {
               
      }
      
    2. 源码:@Conditional(NotReactiveWebApplicationCondition.class) @ConditionalSpring4 新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册 bean 再查看类 NotReactiveWebApplicationCondition

      static class NotReactiveWebApplicationCondition extends NoneNestedConditions {
               
      
      		NotReactiveWebApplicationCondition() {
               
      			super(ConfigurationPhase.PARSE_CONFIGURATION);
      		}
      
      		@ConditionalOnWebApplication(type = Type.REACTIVE)
      		private static class ReactiveWebApplication {
               
      
      		}
      
      	}
      
    3. Spring Cloud Gateway 是基于 WebFlux 的,是 ReactiveWeb,所以 HttpMessageConverters 不会自动注入。于是自己在配置文件中,直接复制源码的 Bean,最终成功。

      # 新建配置类
      @Configuration
      public class WebFluxWithOpenFeignConfig {
               
          @Bean
          @ConditionalOnMissingBean
          public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
               
              return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
          }
      }
      

你可能感兴趣的:(java,spring,spring,boot)