• Spring Cloud Gateway集成Nacos和Swagger聚合Api文档


    一、Gateway服务网关

    1.1 什么是网关

    服务网关又称API网关,是系统对外的唯一入口,封装了系统的内部架构。所有的客户端和消费端,都通过网关接入微服务,在网关层处理非业务逻辑。API网关不是微服务场景中的必须组件,如图没有网关,微服务一样可以对外提供服务
    在这里插入图片描述
    但是对应微服务数量较多,复杂度比较高的系统,使用网关可以带来一些好处

    • 聚合接口,使得服务对调研者透明,降低客户端与服务端的耦合度
    • 聚合后台服务,节省流量,提升用户体验
    • 提供安全,流量控制、API监控、计费等功能

    1.2 Spring Cloud Gateway

    Spring Cloud Gateway做Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,它不仅提供统一的路由方式,并且基于Filter链的方式提供了网关的基本功能。旨在提供一种简单而有些的方法来路由到API。使用Spring Cloud Gateway有如下优点

    • 客户端只与网关交互,降低客户端的复杂度
    • 解决了特定场景的跨越问题
    • 集成actuator,进行监控和健康检查
    • 集成Hystrix,进行服务熔断和限流

    解决的问题:
    在这里插入图片描述

    1.3 其他

    网关除了以上功能外,还可以做如下功能

    • 统一的安全认证(token验证),使用全局过滤器
    • 验证码产生与验证、短信验证码认证,使用自定义端点(RouterFunctions)免校验
    • Swagger的Api文档聚合,集成Swagger,过滤Swagger的端点进行处理
    • 无需认证的配置信息,使用自定义端点免校验

    二、Gateway环境与配置

    2.1 pom.xml

    这块所有的版本都在父工程定义好了

    • SpringBoot 2.6.5
    • SpringCloud 2021.0.1
    • SpringCloudAlibaba 2021.0.1.0

    2.1.1 gateway

    gateway依赖了swagger和openfeign,这两个单独封装成公共包方便使用。自己学习可以合到一起,先看gateway的pom.xml

    <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-configuration-processorartifactId>
            dependency>
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-bootstrapartifactId>
            dependency>
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-gatewayartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-data-redis-reactiveartifactId>
            dependency>
            
            <dependency>
                <groupId>${project.groupId}groupId>
                <artifactId>mms-common-swaggerartifactId>
            dependency>
             
            <dependency>
                <groupId>${project.groupId}groupId>
                <artifactId>mms-common-openfeignartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
    
        dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    2.1.2 sawgger

    swagger的使用前面讲过SpringBoot2.6.5集成Swagger3和Knife3,使用相同的依赖即可,替换上面的mms-common-openfeign

    2.1.3 openfeign

    替换上面的mms-common-swagger

        
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-openfeignartifactId>
            dependency>
            
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
            dependency>
            
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
            dependency>
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-loadbalancerartifactId>
            dependency>
        dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2.2 bootstrap.yml

    server:
      port: 8081
    
    logging:
      level:
        com.alibaba.nacos.client.config.impl: ERROR
    
    management:
      endpoints:
        web:
          exposure:
            include: "health,prometheus"
      endpoint:
        health:
          show-details: always
      metrics:
        tags:
          application: ${spring.application.name}
    
    spring:
      application:
        name: gateway-center
      #设置Web模式为reactive
      main:
        web-application-type: reactive
      cloud:
        nacos:
          discovery:
            namespace: 7d720891-624c-4677-90fe-9004a3f73888
            server-addr: http://192.168.136.133:8848
            file-extension: yml
            # Nacos 服务开启认证时需要配置
            # username: 
            # password: 
            # context-path: nacos
          config:
            namespace: 7d720891-624c-4677-90fe-9004a3f73888
            server-addr: http://192.168.136.133:8848
            file-extension: yml
            # 读取Nacos配置时间(默认3000,单位:毫秒)
            # timeout: 3000
            # Nacos 服务开启认证时需要配置
            # username: 
            # password: 
            # context-path: nacos
      gateway:
        authCenter: user-center
        authCenterUrl: /token/check
        routes:
          - id: user
            uri: lb://user-center
            auth: true
            predicates:
              - Path=/user/**
            filters:
              #使用StripPrefixGatewayFilterFactory分割路由,1代表分割1截。作用是将/user去掉
              - StripPrefix=1
              #使用自定义的
              - ValidateCode=true
            urls:
              - pattern: /user/oauth/**
              - pattern: /user/token/logout
          - id: admin
            uri: lb://admin-service
            auth: true
            predicates:
              - Path=/admin/**
            filters:
              - StripPrefix=1
    
    swagger:
      title: mms cloud API
      license:  Powered By yex
      licenseUrl: https://demo.com/
      terms-of-service-url: https://demo.com/
      contact:
       email: xx@qq.com
       url: https://demo.com/about.html
      authorization:
        name: auth-center
        auth-regex: ^.*$
        authorization-scope-list:
          - scope: server
            description: server all
        token-url-list:
          - http://${GATEWAY-HOST:gateway-center}:${GATEWAY-PORT:8081}/auth/oauth/token
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    三、Swagger聚合配置

    聚合Api文档就是将其他微服务的api文档地址合到一起,形成一个下拉选择。启动网关和用户中心看看效果
    在这里插入图片描述

    3.1 SwaggerProviderConfig

    用于读取gateway的路由配置信息,封装成SwaggerResource,这些信息会在/doc.html页面展示

    @Slf4j
    @Primary
    @Component
    public class SwaggerProviderConfig implements SwaggerResourcesProvider {
    
        public static final String API_URI = "/v3/api-docs";
    
        @Autowired
        private SwaggerProperties swaggerProperties;
    
        @Autowired
        private GatewayProperties gatewayProperties;
    
        @Override
        public List<SwaggerResource> get() {
            List<SwaggerResource> resources = new ArrayList<>();
            Set<String> strings = new HashSet<>();// 记录已经添加过的server
            gatewayProperties.getRoutes().stream()
                    .filter(routeDefinition -> !swaggerProperties.getIgnoreProviders().contains(routeDefinition.getUri().getHost()))
                    .forEach(routeDefinition -> {
                                String url = "/" + routeDefinition.getId() + API_URI;// 拼接url
                                if (!strings.contains(url)) {
                                    strings.add(url);
                                    SwaggerResource swaggerResource = new SwaggerResource();
                                    swaggerResource.setUrl(url);///设置服务文档user-center/v3/api-docs
                                    swaggerResource.setName(routeDefinition.getUri().getHost());//设置服务名user-center
                                    swaggerResource.setSwaggerVersion("3.0");
                                    resources.add(swaggerResource);
                                }
                            }
                    );
            return resources;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    3.2 RouterFunctionConfiguration

    gateway使用的webflux,不支持webmvc。对swagger的路由添加处理器,来处理接口请求

    @Slf4j
    @Configuration
    @AllArgsConstructor
    public class RouterFunctionConfiguration {
    
        private final HystrixFallbackHandler hystrixFallbackHandler
        private final SwaggerSecurityHandler swaggerSecurityHandler;
        private final SwaggerUiHandler swaggerUiHandler;
        private final SwaggerResourceHandler swaggerResourceHandler;
    
        @Bean
        public RouterFunction routerFunction() {
            return RouterFunctions.route(
                    RequestPredicates.path("/fallback")
                            .and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), hystrixFallbackHandler)
                    .andRoute(RequestPredicates.GET("/swagger-resources")
                            .and(RequestPredicates.accept(MediaType.ALL)), swaggerResourceHandler)
                    .andRoute(RequestPredicates.GET("/swagger-resources/configuration/ui")
                            .and(RequestPredicates.accept(MediaType.ALL)), swaggerUiHandler)
                    .andRoute(RequestPredicates.GET("/swagger-resources/configuration/security")
                            .and(RequestPredicates.accept(MediaType.ALL)), swaggerSecurityHandler);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    3.3 SwaggerResourceHandler

    @Slf4j
    @Component
    @AllArgsConstructor
    public class SwaggerResourceHandler implements HandlerFunction<ServerResponse> {
        private final SwaggerResourcesProvider swaggerResources;
    
        /**
         * Handle the given request.
         *
         * @param request the request to handler
         * @return the response
         */
        @Override
        public Mono<ServerResponse> handle(ServerRequest request) {
            return ServerResponse.status(HttpStatus.OK)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(BodyInserters.fromValue(swaggerResources.get()));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.4 SwaggerSecurityHandler

    @Slf4j
    @Component
    public class SwaggerSecurityHandler implements HandlerFunction<ServerResponse> {
        @Autowired(required = false)
        private SecurityConfiguration securityConfiguration;
    
        /**
         * Handle the given request.
         *
         * @param request the request to handler
         * @return the response
         */
        @Override
        public Mono<ServerResponse> handle(ServerRequest request) {
            return ServerResponse.status(HttpStatus.OK)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(BodyInserters.fromValue(
                            Optional.ofNullable(securityConfiguration)
                                    .orElse(SecurityConfigurationBuilder.builder().build())));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    3.5 SwaggerUiHandler

    @Slf4j
    @Component
    public class SwaggerUiHandler implements HandlerFunction<ServerResponse> {
    
        @Autowired(required = false)
        private UiConfiguration uiConfiguration;
    
        /**
         * Handle the given request.
         *
         * @param request the request to handler
         * @return the response
         */
        @Override
        public Mono<ServerResponse> handle(ServerRequest request) {
            return ServerResponse.status(HttpStatus.OK)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(BodyInserters.fromValue(
                            Optional.ofNullable(uiConfiguration)
                                    .orElse(UiConfigurationBuilder.builder().build())));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    四、遇到的问题

    4.1 webflux与mvc不兼容

    webflux与mvc不兼容会导致各种问题
    解决方法一:
    在依赖中排除MVC相关的jar包

    
    <exclusions>
        <exclusion>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        exclusion>
    exclusions>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    排除spring-boot-starter-web之后又可能导致一些类找不到报错,例如我这里使用了CommonResponseDataAdvice implements ResponseBodyAdvice做全局返回值处理,就报ResponseBodyAdvice找不到。排除了CommonResponseDataAdvice 都不行
    解决方法二:
    在配置文件增加如下配置

    spring: 
      #设置Web模式为reactive
      main:
        web-application-type: reactive
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用方案二,完美解决。

    4.2 swagger异常

    swagger文档出不来,f12发现/v3/api-docs报错,检查SwaggerProviderConfig的配置,一般是url配错。反复调试即可解决

  • 相关阅读:
    APS系统能消除造成生产和运输延迟的瓶颈
    SVN服务器搭建+SVN客户端+TeamCity集成环境搭建+VS2019开发
    html使用天地图写一个地图列表
    Vue 使用props为路由组件传参『详解』
    VBA技术资料MF51:VBA_在Excel中突出显示唯一值
    2023华为杯研究生数学建模竞赛CDEF题思路+模型代码
    你应该知道的Linux内核基础及内核编译
    【JAVA】抽象类与接口
    [carla入门教程]-2 pythonAPI的使用
    2022年8月的10篇论文推荐
  • 原文地址:https://blog.csdn.net/yx444535180/article/details/125974436