Spring Cloud Gateway网关下Knife4j文档聚合,以及动态路由的读取和代码配置

一.Knife4j文档聚合

1.1 基础环境明细

我的环境明细如下:

Springboot: 2.7.17
Spring-cloud: 2021.0.7 
Spring-cloud-alibaba:2021.0.5.0
spring-cloud-starter-alibaba-nacos-config:2021.0.5.0
spring-cloud-starter-alibaba-nacos-discovery:2021.0.5.0
Swagger 2
knife4j-gateway-spring-boot-starter:4.5.0
knife4j-openapi2-spring-boot-starter:4.50

至于其他相关环境自行搭建哦,这里不再赘述!捡重要的配置

1.2 集成knife4j

knife4j官网Blog自行查阅: 链接: https://doc.xiaominfo.com/docs/blog/gateway/knife4j-gateway-introduce

1.2.1 maven

		<!--其他模块knife4j-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
            <version>4.5.0</version>
        </dependency>
        <!--网关进行聚合的组件knife4j-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-gateway-spring-boot-starter</artifactId>
            <version>4.5.0</version>
        </dependency>

1.2.2 yml配置

1.2.2.1 其他模块配置
		<!--其他模块knife4j-->
        knife4j:
		  enable: true
		  openapi:
		    title: Knife4j官方文档
		    description: CLOUD-AUTH接口文档(REMOTE)
		    email: xpossess@gmail.com
		    concat: siyu
		    url: https://docs.xiaominfo.com
		    version: v4.0
		    license: Apache 2.0
		    license-url: https://stackoverflow.com/
		    terms-of-service-url: https://stackoverflow.com/
		    group:
		      default:
		        group-name: default   <!--此处可自定义-->
		        api-rule: package
		        api-rule-resources:
		          - com.siyu.controller
1.2.2.2 manual 手动配置模式
		<!--网关进行聚合的组件knife4j-->
        <!--博主这里使用的手动配置-->
        knife4j:
		  gateway:
		    # ① 第一个配置,开启gateway聚合组件
		    enabled: true
		    # ② 第二行配置,设置聚合模式采用discover服务发现的模式
		    strategy: manual #discover 服务发现模式 #manual 手动配置模式
		    basic:
		      enable: true
		      username: *******
		      password: *******
1.2.2.3 discover 服务发现模式
		 <!--自动,服务发现模式-->
		 knife4j:
		   gateway:
		    # ① 第一个配置,开启gateway聚合组件
		      enabled: true
		    # ② 第二行配置,设置聚合模式采用discover服务发现的模式
		      strategy: discover #discover 服务发现模式 #manual 手动配置模式
		      discover:
		      # ③ 第三行配置,开启discover模式
		        enabled: true
		      # ④ 第四行配置,聚合子服务全部为Swagger2规范的文档
		        version: swagger2
		      basic:
		        enable: true
		        username: *******
		        password: *******
1.2.2.3 这里请注意:如果你使用了:SpringSecurity,Sa-token等安全框架请自行开放如下白名单

在这里插入图片描述

1.3 遇到的问题总览并解决

问题1:org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns() 报错 NULL

参考帖子: 链接: Cannot invoke “org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()” because “this.condition” is null

问题2:Failed to start bean ‘documentationPluginsBootstrapper

参考帖子:链接: Failed to start bean ‘documentationPluginsBootstrapper

问题3:访问地址后报404

参考帖子:链接: 访问地址后报404

问题1是我遇到的问题,新解法,问题2,3来自同一篇位置,位置如下图:

在这里插入图片描述

二.Knife4j文档聚合,GateWay网关,动态路由的配置

(我这里逻辑是放一起的,也可以自行逻辑分开)

GateWay当然也可以使用动态路由(感觉path加服务名感觉不nice)

Knife4j(Swagger2)文档聚合也可以使用服务发现模式,有一个问题就是,在切换分组的时候前缀path无法自动加入会报错(所以改成了manual模式,加动态配置路由的方式,嘿嘿!)

2.1 nacos config 配置

2.1.1 创建Data ID:

config-gateway-router

2.1.2 将动态路由的配置填入,并使用TXT的方式

如下格式,多个路由就直接在数组里面添加就行了

[
  {
      "id": "自定义1",
      "uri": "lb://服务名称1", //这里是负责均衡,也可以设置服务的访问路径 IP:PORT
      "predicates": [
          {
              "name": "Path",
              "args": {
                  "pattern": "/服务1path/**"
              }
          }
      ]
  }{
      "id": "自定义2",
      "uri": "lb://服务名称2",
      "predicates": [
          {
              "name": "Path",
              "args": {
                  "pattern": "/服务2path/**"
              }
          }
      ]
  }
]

如下图:
在这里插入图片描述

2.1.3 小插曲

可能有其他读取方式,后续补充!比如yaml中的集合

data:
  - "A"
  - "A"
  - "A"
  - "A"
  - "A"

    可以直接这样获取    
   @ConfigurationProperties(prefix = "data")
    List<String> excludePaths() {
        return new ArrayList<>();
    }

这里knife4j 是沾光了gateway,因为文档聚合的相关属性也是从路由中获取的哦,还有服务名等等,
但是gateway配置的routes是一个对象,从nacos config 读取并转换,额~暂时没想到其他办法,(搞定后)后续更新吧!有其他办法的给我也说说!嘿嘿!

@Validated
public class RouteDefinition {
     private String id;
     private @NotEmpty @Valid List<PredicateDefinition> predicates = new ArrayList();
     private @Valid List<FilterDefinition> filters = new ArrayList();
     private @NotNull URI uri;
     private Map<String, Object> metadata = new HashMap();
     private int order = 0;
 }

2.2 读取配置并操作路由

2.2.1 读取配置初始化

/**
     * 初始化网关路由 nacos config
     */
    private ConfigService initConfigService(){
        try{
            Properties properties = new Properties();
            properties.setProperty("serverAddr", serverAddr);
            if(!StringUtils.isEmpty(namespace))
                properties.setProperty("namespace", namespace);
            properties.setProperty("username", username);
            properties.setProperty("password", password);
            return configService = NacosFactory.createConfigService(properties);
        } catch (Exception e) {
            log.error("初始化网关路由时发生错误",e);
            return null;
        }
    }

    @PostConstruct
    public void dynamicRouteByNacosListener() {
        try {
            if(StringUtils.isEmpty(group))
                group = "";
            configService = initConfigService();
            if(configService == null){
                log.warn("initConfigService 失败!");
                return;
            }
            String configInfo = configService.getConfig(dataId, group, 3000);
            List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
            log.info("[->获取<-]到dataId为{},group为{}的配置内容:{}",dataId,group,definitionList);
            for(RouteDefinition definition : definitionList){
                log.info("从nacos动态获取到的路由配置为 : {}",definition.toString());
                addGateWayRoute(definition);//添加gateway路由
                addKnife4jRoute(definition);//添加knife4j-gateway路由(开启手动配置模式)
            }
        } catch (NacosException e) {
            log.error("发生错误!", e);
        }
        dynamicRouteByNacosListener(dataId, group);//监听该Data ID 
    }
2.2.2 添加gateway路由
    /**
     * 添加网关路由
     * @param definition
     */
    private void addGateWayRoute(RouteDefinition definition) {
        log.info("开始添加Gateway路由配置 {}",definition);
        try {
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
        log.info("添加Gateway路由成功 {}",definition);
        } catch (Exception e) {
            log.error("发生错误!", e);
        }
    }
2.2.3 添加knife4j-gateway路由

有一个问题:如果swagger group为自自定义名称,此处的逻辑需要修改哦,博主文章中统一使用的default,根据实际需求,如果有分多个接口文档组的话,额~,后续有空再补充吧,哈哈

    /**
     * 向Knife4jGatewayProperties中添加路由
     * @param definition 网关路由对象
     */
    private void addKnife4jRoute(RouteDefinition definition) {
        log.info("开始添加Knife4j路由配置 {}",definition);
        Knife4jGatewayProperties.Router router = new Knife4jGatewayProperties.Router();
        router.setName(definition.getId());
        router.setServiceName(definition.getUri().getHost());
        definition.getPredicates().forEach(predicate -> {
            if (Objects.equals(predicate.getName(), "Path")) {
                String replace = predicate.getArgs().get("pattern").replace("/**", "").replace("/*", "");
                router.setUrl(replace + router.getUrl());
            }
        });
        knife4jGatewayProperties.getRoutes().add(router);
        log.info("添加Knife4j路由成功,当前路由配置为 {}", JSONObject.toJSONString(knife4jGatewayProperties.getRoutes()));
    }

2.3 监听配置的变化并操作路由

/**
     * 监听Nacos下发的动态路由配置
     */
    public void dynamicRouteByNacosListener (String dataId, String group){
        try {
            configService.addListener(dataId, group, new Listener()  {
                @Override
                public void receiveConfigInfo(String configInfo) {
                    List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
                    log.info("[->监听<-]到dataId为{},de group为{}的配置发生变更,配置内容:{}",dataId,group,definitionList);
                    updateGateWayRoute(definitionList);//更新gateway路由
                    updateKnife4jRoute(definitionList);//更新Knife4j-gateway路由
                }
                @Override
                public Executor getExecutor() {
                    log.info("getExecutor");
                    return null;
                }
            });
        } catch (NacosException e) {
            log.error("从nacos接收动态路由配置出错!!!",e);
        }
    }
2.3.1 更新gateway路由
/**
     * 更新路由
     * @param definition 集合
     */
    private void updateGateWayRoute(List<RouteDefinition> definition) {
        definition.stream().iterator().forEachRemaining(route -> {
            log.info("开始更新路由配置 {},先删除路由,再重新添加路由",route);
            try {
                routeDefinitionWriter.delete(Mono.just(route.getId()));
                routeDefinitionWriter.save(Mono.just(route)).subscribe();
                this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
                log.info("更新路由配置成功 {}", route);
            } catch (Exception e) {
                log.error("更新路由配置失败:\r\n"+e);
            }
        });
    }
2.3.1 更新knife4j-gateway路由
/**
     * 更新Knife4j路由
     * @param gatewayRouteDefinition 网关路由配置集合
     */
    public void updateKnife4jRoute(List<RouteDefinition> gatewayRouteDefinition){
        //删除不需要的路由
        knife4jGatewayProperties.getRoutes().stream()
                .filter(router -> !gatewayRouteDefinition.stream().map(RouteDefinition::getId).collect(Collectors.toList()).contains(router.getName()))
                .collect(Collectors.toList()).iterator().forEachRemaining(router -> {
                    log.info("开始删除Knife4j路由配置 {}",router.getName());
                    knife4jGatewayProperties.getRoutes().remove(router);
        });
        //添加需要的路由
        gatewayRouteDefinition.stream()
                .filter(route -> !knife4jGatewayProperties.getRoutes().stream().map(Knife4jGatewayProperties.Router::getName).collect(Collectors.toList()).contains(route.getId()))
                .collect(Collectors.toList()).iterator().forEachRemaining(route -> {
                    log.info("开始添加Knife4j路由配置 {}", route.getId());
                    addKnife4jRoute(route);
                });
    }

2.4 完整代码展示(相关变量自行配置注入)

package com.siyu.cloudgateway.routes;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.github.xiaoymin.knife4j.spring.gateway.Knife4jGatewayProperties;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
 * @author Siyu
 * @date 2024/06/19 19:34
 * @description 动态配置Route 包括Gateway和Knife4j
 */
@Slf4j
@RefreshScope
@Component
public class DynamicRouteByGateWayAndKnife4jForNacosConfig implements ApplicationEventPublisherAware {
    @Value("${gateway.data-id}")
    private String dataId;
    @Value("${spring.cloud.nacos.config.group}")
    private String group = "remote";
    @Value("${spring.cloud.nacos.config.server-addr}")
    private String serverAddr;
    @Value("${spring.cloud.nacos.config.namespace}")
    private String namespace;
    @Value("${spring.cloud.nacos.config.username}")
    private String username;
    @Value("${spring.cloud.nacos.config.password}")
    private String password;

    @NacosInjected
    private ConfigService configService;
    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;
    @Resource
    private Knife4jGatewayProperties knife4jGatewayProperties;

    private  ApplicationEventPublisher applicationEventPublisher;

    @Override
    public void setApplicationEventPublisher(@NotNull ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
    /**
     * 初始化网关路由 nacos config
     */
    private ConfigService initConfigService(){
        try{
            Properties properties = new Properties();
            properties.setProperty("serverAddr", serverAddr);
            if(!StringUtils.isEmpty(namespace))
                properties.setProperty("namespace", namespace);
            properties.setProperty("username", username);
            properties.setProperty("password", password);
            return configService = NacosFactory.createConfigService(properties);
        } catch (Exception e) {
            log.error("初始化网关路由时发生错误",e);
            return null;
        }
    }

    @PostConstruct
    public void dynamicRouteByNacosListener() {
        try {
            if(StringUtils.isEmpty(group))
                group = "";
            configService = initConfigService();
            if(configService == null){
                log.warn("initConfigService 失败!");
                return;
            }
            String configInfo = configService.getConfig(dataId, group, 3000);
            List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
            log.info("[->获取<-]到dataId为{},group为{}的配置内容:{}",dataId,group,definitionList);
            for(RouteDefinition definition : definitionList){
                log.info("从nacos动态获取到的路由配置为 : {}",definition.toString());
                addGateWayRoute(definition);
                addKnife4jRoute(definition);
            }
        } catch (NacosException e) {
            log.error("发生错误!", e);
        }
        dynamicRouteByNacosListener(dataId, group);
    }



    /**
     * 监听Nacos下发的动态路由配置
     */
    public void dynamicRouteByNacosListener (String dataId, String group){
        try {
            configService.addListener(dataId, group, new Listener()  {
                @Override
                public void receiveConfigInfo(String configInfo) {
                    List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
                    log.info("[->监听<-]到dataId为{},de group为{}的配置发生变更,配置内容:{}",dataId,group,definitionList);
                    updateGateWayRoute(definitionList);
                    updateKnife4jRoute(definitionList);
                }
                @Override
                public Executor getExecutor() {
                    log.info("getExecutor");
                    return null;
                }
            });
        } catch (NacosException e) {
            log.error("从nacos接收动态路由配置出错!!!",e);
        }
    }
    /**
     * 更新路由
     * @param definition 集合
     */
    private void updateGateWayRoute(List<RouteDefinition> definition) {
        definition.stream().iterator().forEachRemaining(route -> {
            log.info("开始更新路由配置 {},先删除路由,再重新添加路由",route);
            try {
                routeDefinitionWriter.delete(Mono.just(route.getId()));
                routeDefinitionWriter.save(Mono.just(route)).subscribe();
                this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
                log.info("更新路由配置成功 {}", route);
            } catch (Exception e) {
                log.error("更新路由配置失败:\r\n"+e);
            }
        });
    }
    /**
     * 更新Knife4j路由
     * @param gatewayRouteDefinition 网关路由配置集合
     */
    public void updateKnife4jRoute(List<RouteDefinition> gatewayRouteDefinition){
        //删除不需要的路由
        knife4jGatewayProperties.getRoutes().stream()
                .filter(router -> !gatewayRouteDefinition.stream().map(RouteDefinition::getId).collect(Collectors.toList()).contains(router.getName()))
                .collect(Collectors.toList()).iterator().forEachRemaining(router -> {
                    log.info("开始删除Knife4j路由配置 {}",router.getName());
                    knife4jGatewayProperties.getRoutes().remove(router);
        });
        //添加需要的路由
        gatewayRouteDefinition.stream()
                .filter(route -> !knife4jGatewayProperties.getRoutes().stream().map(Knife4jGatewayProperties.Router::getName).collect(Collectors.toList()).contains(route.getId()))
                .collect(Collectors.toList()).iterator().forEachRemaining(route -> {
                    log.info("开始添加Knife4j路由配置 {}", route.getId());
                    addKnife4jRoute(route);
                });
    }

    /**
     * 向Knife4jGatewayProperties中添加路由
     * @param definition 网关路由对象
     */
    private void addKnife4jRoute(RouteDefinition definition) {
        log.info("开始添加Knife4j路由配置 {}",definition);
        Knife4jGatewayProperties.Router router = new Knife4jGatewayProperties.Router();
        router.setName(definition.getId());
        router.setServiceName(definition.getUri().getHost());
        definition.getPredicates().forEach(predicate -> {
            if (Objects.equals(predicate.getName(), "Path")) {
                String replace = predicate.getArgs().get("pattern").replace("/**", "").replace("/*", "");
                router.setUrl(replace + router.getUrl());
            }
        });
        knife4jGatewayProperties.getRoutes().add(router);
        log.info("添加Knife4j路由成功,当前路由配置为 {}", JSONObject.toJSONString(knife4jGatewayProperties.getRoutes()));
    }
    /**
     * 添加网关路由
     * @param definition
     */
    private void addGateWayRoute(RouteDefinition definition) {
        log.info("开始添加Gateway路由配置 {}",definition);
        try {
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
        log.info("添加Gateway路由成功 {}",definition);
        } catch (Exception e) {
            log.error("发生错误!", e);
        }
    }
}

三.效果展示

3.1 聚合状态呈现

在这里插入图片描述
点击每一个分组会自动调用其他模块的swagger分组数据

在这里插入图片描述

3.2 测试网关服务-调用其他模块的服务

略,根据实际情况自行测试和验证

四. 结束语

4.1 相关说明:

这里集成的Swagger2规范,如果是Swagger3,很多不一样的地方:yaml配置,maven,静态资源path放行 等不一样哦,其他请自行踩坑或者查询官方集成Blog:比如Spring boot 3+的版本,Swagger3

有空后面再折腾Swagger3,如果有其他集成博文可以@,私信我呀,资源共享嘛,哈哈!

此篇文章有借鉴其他文章的内容并融合而成:介意请联系修改呀!

有其他问题请在文章评论留下各位的宝贵意见(听劝),私信或者邮箱联系呀:910380566@qq.com

索取的同时也做做贡献,和各位一起成长,逐渐成为大佬而不断努力。同时也记录一下开发的经验和思路。

  • 32
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: cloud-nacos-gateway-knife4j:swagger聚合文档是使用Spring Cloud和Nacos作为技术栈开发的一种解决方案。 Spring Cloud是一套开发分布式应用的工具集,它基于Spring Boot,用于构建微服务架构的应用程序。它提供了诸如服务注册与发现服务追踪、负载均衡等功能,可以方便地实现微服务的开发和管理。在这个解决方案中,我们使用了Spring Cloud来构建和管理微服务。 Nacos是一个动态服务发现配置管理和服务管理平台。它提供了服务注册与发现配置管理、动态路由等功能,可以方便地实现微服务的注册与发现配置的动态管理。在这个解决方案中,我们将使用Nacos作为服务注册与发现的中心。 GatewaySpring Cloud网关组件,它以微服务的方式构建网关,提供了统一的入口和出口,可以对请求进行路由、过滤、聚合等多种操作。在这个解决方案中,我们使用Gateway作为网关组件,统一管理和分发请求。 Knife4j是一个开源的Swagger文档聚合工具,它可以将多个微服务的Swagger文档聚合在一起,提供一个统一的API文档入口。在这个解决方案中,我们使用Knife4j聚合各个微服务的Swagger文档,方便开发人员查看和调试API接口。 综上所述,cloud-nacos-gateway-knife4j:swagger聚合文档使用了Spring Cloud、Nacos、GatewayKnife4j等技术,通过Spring Cloud构建和管理微服务,使用Nacos实现服务注册与发现,通过Gateway实现统一的请求分发和路由,再通过Knife4j将各个微服务的Swagger文档聚合在一起,方便开发人员进行API的查看和调试。这个解决方案可以提高开发效率、简化架构,使得微服务的开发和管理更加方便和高效。 ### 回答2: cloud-nacos-gateway-knife4j是基于Spring Cloud、Nacos、GatewayKnife4j等技术实现的Swagger聚合文档工具。 首先,这个工具使用了Spring Cloud框架,它是一种用于构建分布式系统的解决方案。Spring Cloud提供了一系列插件和组件,使得我们可以轻松地构建、部署和管理分布式应用。这些组件包括服务发现与注册、服务间调用、负载均衡、断路器等等。在cloud-nacos-gateway-knife4j中,我们使用Spring Cloud来实现服务注册与发现的功能,使得不同的微服务可以方便地相互调用。 其次,cloud-nacos-gateway-knife4j还使用了Nacos作为服务的注册中心。Nacos是一个开源的动态服务发现配置服务管理平台,它提供了服务注册、服务发现服务配置路由配置等功能。在cloud-nacos-gateway-knife4j中,我们使用Nacos作为服务注册中心,来管理微服务的地址和配置信息。 另外,cloud-nacos-gateway-knife4j还使用了Gateway作为API网关。API网关是系统的统一入口,它可以处理一些通用的非业务功能,如身份认证、请求转发、限流等等。在cloud-nacos-gateway-knife4j中,我们使用Gateway作为API网关,实现了请求的转发和一些基本的安全控制功能。 最后,cloud-nacos-gateway-knife4j还使用了Knife4j作为Swagger的UI界面。Swagger是一种用于构建、文档化和调试RESTful接口的工具,它提供了一套非常直观的界面来展示接口信息和测试接口。在cloud-nacos-gateway-knife4j中,我们使用Knife4j来生成并展示聚合文档,使得接口文档更加友好和易用。 总的来说,cloud-nacos-gateway-knife4j是一个基于Spring Cloud、Nacos、GatewayKnife4j等技术实现的Swagger聚合文档工具。它利用这些技术的优势,帮助开发者更好地管理和维护微服务,并提供了友好的界面来查看和测试接口文档。 ### 回答3: Cloud-Nacos-Gateway-Knife4j 是一个使用 Spring Cloud 和 Nacos 技术实现的聚合文档,其中集成了 Swagger。它可以帮助开发者更便捷地查看和管理项目的 API 文档Spring Cloud 是一个开发微服务架构的框架,提供了许多功能,例如服务注册与发现配置管理、负载均衡等。Nacos 是一个用于服务注册与发现、动态配置管理的平台,可以实现服务的自动发现配置更新。这两个技术结合起来,可以方便地构建和管理微服务架构。 Cloud-Nacos-Gateway-Knife4j 中的 Gateway 是一个 API 网关,它可以承担路由和负载均衡的作用,将外部请求转发给后端的微服务Knife4j 是一个为 Swagger 提供增强功能的工具,可以生成美观的 API 文档,并提供了在线测试接口的功能。 在使用 Cloud-Nacos-Gateway-Knife4j 架构时,我们可以通过 Nacos 注册中心管理和发现微服务,以及实现动态的配置更新。Gateway 作为入口,将外部请求转发到相应的微服务。同时,我们可以使用 Knife4j 生成并展示微服务的 API 文档,便于开发者查看和调试接口。 总之,Cloud-Nacos-Gateway-Knife4j 提供了一种基于 Spring Cloud 和 Nacos 的微服务架构解决方案,提供了服务注册发现配置管理、API 文档和在线测试等功能,为开发者带来了更加便捷和高效的开发体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值