网关的动态路由 之前已经对网关的简单使用有了一个初步的了解,并且对于配置中心对配置的管理也有了一个简单的了解。 那么,很显然,靠着网关在配置文件里面配置好的路由路径是比较死板的,动态路由是一个很重要的东西,以此减少对代码的修改。 Spring Gateway的动态路由功能允许根据特定的规则在运行动态配置路由,而无需重新启动应用,比较常见的方式是通过数据库、配置中心或者API来加载或更新路由规则,于此,介绍以下采用配置中心实现动态路由的方式。 在该实现中,采用Nacos作为配置中心。
网关 + Nacos配置中心实现的动态路由 首先,引入nacos配置中心和注册中心的依赖。而后,对于配置文件:
1 2 3 spring.cloud .gateway .discovery .locator .enabled=true spring.cloud .gateway .discovery .locator .lower-case-service-id=true spring.cloud .gateway .discovery .locator .filters [0] =StripPrefix=1
在这部分中,启用了通过服务发现的方式来动态路由,并将服务ID转化为小写,还应用了StripPrefix 过滤器来去掉路径中的前缀。 换言之,之前断言中的Path还是http://localhost:19088的话,现在就可以用lb://user-auth-service。 接着,是对于nacos的一系列配置,不详述。
1 2 3 management.endpoint.health.show-details =alwaysmanagement.endpoint.gateway.enabled =true management.endpoints.web.exposure.include =*
对于如上的配置,与Spring Boot管理端点和监控有关,用于监控的。比如management.endpoint.gateway.enabled=true:启用 Spring Cloud Gateway 的管理端点,可以通过该端点查看网关的路由信息。 在配置好nacos的相关信息后:
1 2 3 4 spring.cloud.gateway.default-filters=DedupeResponseHeader=Access-Control-Allow-Origin, RETAIN_UNIQUE spring.cloud.gateway.globalcors.corsConfigurations..allowedHeaders=* spring.cloud.gateway.globalcors.corsConfigurations..allowedMethods=* spring.cloud.gateway.globalcors.corsConfigurations..allowedOrigins=*
这部分配置与 Spring Cloud Gateway 的默认过滤器和跨域资源共享(CORS)设置有关。 spring.cloud.gateway.default-filters[0]=DedupeResponseHeader=Access-Control-Allow-Origin, RETAIN_UNIQUE:该配置确保在响应头中,Access-Control-Allow-Origin 只保留唯一值,避免重复的 CORS 头信息。 另外几个是CORS的配置。allowedHeaders=*:允许所有请求头。allowedMethods=*:允许所有 HTTP 方法(GET, POST, etc.)。allowedOrigins=*:允许所有来源访问。这些配置确保 Gateway 允许跨域请求,并清理重复的 CORS 响应头。 网关的路由配置文件为:gateway-router.json。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [{ "filters" : [{ "args" : { "parts" : "1" }, "name" : "StripPrefix" }], "id" : "user-auth-service" , "order" : 0 , "predicates" : [{ "args" : { "pattern" : "/auth/**" }, "name" : "Path" }], "uri" : "lb://user-auth-service" }, …… ]
这是一个json列表,gateway后续会对其进行解析以实现路由的配置。 为了实现动态路由,首先创建一个配置类DynamicRouteConfig,该配置类的作用是定义如何从 Nacos 加载路由信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Configuration public class DynamicRouteConfig { @Resource private ApplicationEventPublisher publisher; @Value("${spring.cloud.nacos.config.router-data-id:gateway-router.json} " ) private String routerDataId; @Configuration public class NacosDynRoute { @Resource private NacosConfigProperties nacosConfigProperties; @Bean public NacosRouteDefinitionRepository nacosRouteDefinitionRepository() { return new NacosRouteDefinitionRepository(routerDataId, publisher, nacosConfigProperties); } } }
这里,我们定义了一个名为 NacosDynRoute 的内部配置类,注入了 NacosConfigProperties,并创建了 NacosRouteDefinitionRepository 的 Bean。 NacosRouteDefinitionRepository 是实现 RouteDefinitionRepository 接口的自定义实现,用于从 Nacos 中读取路由配置。该类包含以下主要功能: 构造函数: 初始化时注册了 Nacos 配置监听器。
1 2 3 4 5 6 public NacosRouteDefinitionRepository(String routerDataId, ApplicationEventPublisher publisher, NacosConfigProperties nacosConfigProperties) { this .routerDataId = routerDataId; this .publisher = publisher; this .nacosConfigProperties = nacosConfigProperties; addListener(); }
获取路由定义: 从 Nacos 中读取路由配置,解析成 RouteDefinition 列表,并返回 Flux 类型。
1 2 3 4 5 6 7 8 9 10 11 @Override public Flux<RouteDefinition> getRouteDefinitions() { try { String content = nacosConfigProperties.configServiceInstance().getConfig(routerDataId, nacosConfigProperties.getGroup(), 5000 ); List<RouteDefinition> routeDefinitions = getListByStr(content); return Flux.fromIterable (routeDefinitions) ; } catch (NacosException e) { log.error ("getRouteDefinitions by nacos error" , e); } return Flux.fromIterable (Collections.EMPTY_LIST) ; }
添加 Nacos 配置监听器: 当配置发生变化时,发布 RefreshRoutesEvent 事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private void addListener ( ) { try { nacosConfigProperties.configServiceInstance ().addListener (routerDataId, nacosConfigProperties.getGroup (), new Listener () { @Override public Executor getExecutor ( ) { return null ; } @Override public void receiveConfigInfo (String configInfo ) { publisher.publishEvent (new RefreshRoutesEvent (this )); } }); } catch (NacosException e) { log.error ("nacos-addListener-error" , e); } }
靠着这个监听器,可以监听配置的变化。 最后,通过:
1 2 3 4 5 6 private List <RouteDefinition > getListByStr (String content ) { if (StringUtils .isNotEmpty (content)) { return JSON Object .parseArray (content, RouteDefinition .class ); } return new ArrayList <>(0 ); }
将从 Nacos 获取的 JSON 字符串解析为 RouteDefinition 对象列表。 至此,Nacos 动态路由实现完成。 使用 Nacos 动态加载 Spring Cloud Gateway 的路由配置。DynamicRouteConfig 配置类用于定义从 Nacos 加载路由的 Bean,NacosRouteDefinitionRepository 则实现了从 Nacos 获取路由定义的逻辑,并处理了路由配置变更的监听。这样,网关可以根据 Nacos 配置的变化自动刷新路由规则,实现动态路由配置的功能。 在使用时,只需要在nacos配置中心中配置路由的json文件即可。详细实现可见:https://github.com/gagaducko/springcloud-microservice-security/tree/main/gateway-service