当前位置: 代码迷 >> 综合 >> Spring Cloud Gateway 采用 OpenFeign 远程调用失败的解决方案
  详细解决方案

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

热度:12   发布时间:2023-12-08 12:51:48.0

文章目录

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

一、框架版本
  • 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 {
          @Resourceprivate AuthenticationService authenticationService;@PostMapping("/auth")public Boolean checkAuth(@RequestBody @Valid BaseRequest baseRequest) {
          log.info("<-------------------------->");return authenticationService.checkAuth(baseRequest);}
    }
    
  • 网关引用 OpenFeign 依赖

    <!-- OpenFeign -->
    <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>2.2.2.RELEASE</version>
    </dependency>
    
  • 网关 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@ConditionalOnMissingBeanpublic HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
              return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));}
      }
      
  相关解决方案