Spring Cloud Gateway2之路由详解
Spring Cloud Gateway路由
文章目录
- 1. 前言
- 2. Gateway路由的基本概念
- 3. 三种路由
- 1. 静态路由
- 2. 动态路由
- 1. 利用外部存储
- 2. API动态路由
- 3. 服务发现路由(自动路由)
- 3.1. 配置方式
- 3.2 自动路由(服务发现)原理
- 核心源码
- GatewayDiscoveryClientAutoConfiguration
- `DiscoveryClientRouteDefinitionLocator`核心方法`getRouteDefinitions`
- 4. Gateway路由的核心组件
- 4.1 路由断言
- 组合并生效相当于并且的关系
- 如果要或的关系需要分配多个路由
- 4.2 路由过滤器
- 路由过滤器概念
- 路由过滤器工厂
- 内置路由过滤器
- 自定义路由过滤器
- 5. 路由的动态刷新
- 5.1. 添加依赖
- 5.2. 配置application.yml
- 5.3. 创建Config Server
- 5.4. 在远程Git仓库中添加配置文件
- 5.5. 启动Gateway服务
- 5.6. 动态刷新路由信息
- 6. 处理路由失败和异常
- 6.1 处理请求失败和异常
- 6.2 配置回退和重试策略
- 7. 高级路由功能
- 8. 参考文档
1. 前言
其实Spring Cloud Gateway2.x 的官网文档写的已经很全面了,如果想要了解,可以访问 《Spring Cloud Gateway》
Spring Cloud Gateway是一个基于Spring Boot构建的API网关,主要用于微服务架构中。它提供了一种简单而高效的方式来对请求进行路由、过滤和转发,从而实现对服务的统一访问入口和流量管理。Spring Cloud Gateway通过一个高度可配置的路由规则集,支持各种复杂的请求处理场景。
与传统的API网关(如Zuul)相比,Spring Cloud Gateway提供了更好的性能和丰富的功能。它基于响应式编程模型(Reactive)和Spring WebFlux框架构建,能够提供非阻塞的异步I/O处理,并且能够很好地与其他Spring Cloud组件进行集成。此外,Spring Cloud Gateway还提供了很多现成的功能,如负载均衡、熔断、限流等,可以帮助开发者快速搭建一个完善的API网关。
图片来自Spring Cloud Gateway2 官网 https://cloud.spring.io/spring-cloud-gateway/2.0.x/single/spring-cloud-gateway.html
2. Gateway路由的基本概念
- 2.1 路由的定义和作用
路由是一个HTTP请求的处理过程。在Spring Cloud Gateway中,每个请求都会经过一系列的过滤器,最后转发到目标URI。
路由配置由三部分组成:ID、目标URI、一系列的断言和过滤器。ID是路由的唯一标识,目标URI是请求的最终目的地,断言是用来匹配HTTP请求的规则,过滤器是用来处理HTTP请求的组件。
在Spring Cloud Gateway中配置路由有两种方式:通过配置文件和通过代码。
- 通过配置文件配置路由:
在application.yml文件中添加如下配置:
spring:cloud:gateway:routes:- id: user_routeuri: http://localhost:8080predicates:- Path=/user/**
以上面的配置为例,id为user_route的路由会匹配所有路径为/user/的请求,然后将其转发到http://localhost:8080。
- 通过代码配置路由:
在配置类中添加如下配置:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {return builder.routes().route("user_route", r -> r.path("/user/**").uri("http://localhost:8080")).build();
}
以上面的配置为例,id为user_route的路由会匹配所有路径为/user/的请求,然后将其转发到http://localhost:8080。
- 2.2 如何在Spring Cloud Gateway中配置路由
3. 三种路由
根据路由的创建方式和使用场景,可以将路由分类为以下三种:
1. 静态路由
在Spring Cloud Gateway启动时,通过配置文件或Java代码定义的路由规则。这些路由规则在运行时是不可修改的。
可以通过配置文件定义静态路由:这段配置会将所有以/user开始的请求转发到http://localhost:8080。
spring:cloud:gateway:routes:- id: user_routeuri: http://localhost:8080predicates:- Path=/user/**
Spring Cloud Gateway的静态路由实现的原理主要通过Reactive模式下的Netty处理方式,以及Project Reactor中的Flux和Mono模型来处理并发请求。此外,它还使用了Spring 5的核心Webflux框架进行路由分发。
具体来说,当请求到来时,Spring Cloud Gateway会根据配置文件中的静态路由信息,将请求转发到相应的目标地址。
核心的代码主要集中在RoutePredicateHandlerMapping和FilteringWebHandler类中。
// RoutePredicateHandlerMapping用于处理请求的映射关系
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {public RoutePredicateHandlerMapping(GatewayProperties properties, RouteLocator routeLocator, ProxyExchangeArgumentResolver proxyExchangeArgumentResolver, ServerCodecConfigurer serverCodecConfigurer, Environment environment) {...}...
}// FilteringWebHandler用于处理各种过滤器
public class FilteringWebHandler implements WebHandler {private final List<GlobalFilter> globalFilters;public FilteringWebHandler(List<GlobalFilter> globalFilters) {this.globalFilters = globalFilters;}...
}
实际上,配置静态路由的主要工作量在于编写配置文件和理解路由断言,Spring Cloud Gateway已经为处理了复杂的路由转发和过滤器操作。
具体的路由匹配和转发过程则由Spring Cloud Gateway框架自动处理。在处理请求时,Gateway会依次经过负载均衡器、过滤器链和路由断言的处理,并最终将请求转发到配置的目标地址。
2. 动态路由
动态路由通常可以理解为两种方式,一种通过外部配置存储动态更新网关路由,另一种是通过API 的方式动态新增修改删除网关路由。
1. 利用外部存储
动态路由与静态路由的主要区别在于,动态路由允许在运行时更新路由配置,而不需要重启应用。Spring Cloud Gateway
支持通过配置中心(如Spring Cloud Config
)。
实现动态路由的原理主要是通过监听配置中心的变化,当配置发生变化时,使用Event机制触发路由信息的更新。Spring Cloud Gateway会自动处理新的路由配置并更新其内部的路由表。
核心代码主要集中在以下几个类中:
当配置中心发生更改时,RouteRefreshListener会监听到相关事件,触发RefreshRoutesEvent事件,从而使CachingRouteLocator更新路由信息。这样,Spring Cloud Gateway就可以在运行时动态地处理新的路由配置。
CachingRouteLocator
:它负责缓存和管理路由信息,同时也会处理路由信息的更新。
public abstract class CachingRouteLocator implements RouteLocator, ApplicationListener<RefreshRoutesEvent> {public abstract Flux<Route> fetch();@Overridepublic void onApplicationEvent(RefreshRoutesEvent event) {// 当收到一个RefreshRoutesEvent事件时,将会触发路由信息的更新this.resetRoutes().subscribe();}...
}
RouteDefinitionRouteLocator
:它继承自CachingRouteLocator
,并负责从RouteDefinitionLocator
中获取路由定义,然后根据路由定义创建路由。
public class RouteDefinitionRouteLocator extends CachingRouteLocator {public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator, List<GatewayFilterFactory> gatewayFilters, List<RoutePredicateFactory> routePredicates, RouteDefinitionHandlerFilter routeDefinitionHandlerFilter, ConfigurationService configurationService, GatewayProperties properties) {...}...
}
- RouteRefreshListener:它负责监听配置中心的变化,并在检测到更改时发布一个RefreshRoutesEvent事件。
@Configuration
public class RouteRefreshListener {@Beanpublic ApplicationListener<?> routeChangeListener(RouteDefinitionRouteLocator routeDefinitionRouteLocator) {return new ApplicationListener<RefreshRoutesResultEvent>() {@Overridepublic void onApplicationEvent(RefreshRoutesResultEvent event) {routeDefinitionRouteLocator.onApplicationEvent(new RefreshRoutesEvent(this));}};}
}
要实现动态路由,还需要在配置文件中配置相应的配置中心,例如使用Spring Cloud Config:
spring:cloud:gateway:discovery:locator:enabled: trueroutes:- id: dynamic_routeuri: lb://service-idpredicates:- Path=/dynamic_path/**config:uri: http://config-server-urilabel: mastername: gateway
2. API动态路由
在Spring Cloud Gateway运行时,通过调用API动态创建和修改的路由规则。这种路由规则可以根据需要进行实时的修改。动态路由通常需要通过编程方式创建。
在Spring Cloud Gateway中,可以通过调用Gateway API来动态地创建和修改路由规则。这些路由规则可以在运行时进行实时修改。要实现这一功能,需要使用RouteDefinitionWriter
接口,它提供了添加、删除和更新路由定义的方法。
Spring Cloud Gateway中动态地创建和修改路由规则
依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
创建一个RouteController
来处理动态路由的创建、更新和删除操作
@RestController
@RequestMapping("/route")
public class RouteController {@Autowiredprivate RouteDefinitionWriter routeDefinitionWriter;@Autowiredprivate RouteDefinitionLocator routeDefinitionLocator;@PostMappingpublic Mono<Void> add(@RequestBody RouteDefinition routeDefinition) {return routeDefinitionWriter.save(Mono.just(routeDefinition)).then();}@PutMappingpublic Mono<Void> update(@RequestBody RouteDefinition routeDefinition) {return routeDefinitionWriter.delete(Mono.just(routeDefinition.getId())).then(routeDefinitionWriter.save(Mono.just(routeDefinition))).then();}@DeleteMapping("/{id}")public Mono<Void> delete(@PathVariable String id) {return routeDefinitionWriter.delete(Mono.just(id));}@GetMappingpublic Flux<RouteDefinition> getRoutes() {return routeDefinitionLocator.getRouteDefinitions();}
}
在这个例子中,使用RouteDefinitionWriter
保存、更新和删除路由定义。当定义新的路由规则或者更新现有的路由规则时,会自动触发路由表的刷新。
现在就可以使用HTTP API来动态地创建、修改和删除路由规则了:
-
添加一个新的路由规则:
POST /route {"id": "my_route","uri": "http://example.com","predicates": [{"name": "Path","args": {"pattern": "/mypath/**"}}],"filters": [{"name": "RewritePath","args": {"regexp": "/mypath/(?<segment>.*)","replacement": "/${segment}"}}] }
-
更新现有的路由规则:
PUT /route {"id": "my_route","uri": "http://example.com","predicates": [{"name": "Path","args": {"pattern": "/mypath_v2/**"}}],"filters": [{"name": "RewritePath","args": {"regexp": "/mypath_v2/(?<segment>.*)","replacement": "/${segment}"}}] }
-
删除现有的路由规则:
DELETE /route/my_route
通过这种方法,可以在Spring Cloud Gateway运行时动态地创建和修改路由规则,以满足不断变化的业务需求。
3. 服务发现路由(自动路由)
3.1. 配置方式
这是一种特殊的动态路由,其路由规则是根据服务发现机制来自动创建的。
在微服务架构中,服务发现是一种特别重要的机制,它让微服务能够自动地发现网络中的其他服务,并知道如何与它们进行交互。Spring Cloud Gateway通过与服务注册中心(如Eureka、Consul等)集成,实现了自动的服务发现路由功能。
当一个新的服务实例被注册到服务注册中心时,Spring Cloud Gateway会自动发现它,并创建一个新的路由规则,将请求转发到这个服务。同样,当一个服务实例下线或被注销时,对应的路由规则也会被自动删除,这就是所谓的服务发现路由或者自动路由。
这种机制可以极大地简化服务间的交互,因为不需要手动地为每一个服务定义路由规则。
在Spring Cloud Gateway中使用服务发现的一个简单示例
添加 Spring Cloud Gateway和 Eureka的依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
application.yml
文件中配置Eureka和Gateway:
spring:cloud:gateway:discovery:locator:enabled: true # 启用服务发现路由application:name: gateway-service
eureka:client:service-url:defaultZone: http://localhost:8761/eureka/
启动Eureka Server和的服务,然后启动Spring Cloud Gateway,Gateway就会自动发现注册在Eureka中的服务,并为它们创建路由规则。例如有一个名为user-service
的服务,那么就可以通过http://localhost:8080/user-service
来访问。
3.2 自动路由(服务发现)原理
在Spring Cloud Gateway中实现服务发现路由的核心类是DiscoveryClientRouteDefinitionLocator
。这个类负责从注册中心获取服务实例信息,并基于这些信息创建路由定义。当服务实例发生变化时,DiscoveryClientRouteDefinitionLocator
会自动更新路由定义。
服务发现路由的底层原理主要包括以下几个方面:
-
集成服务发现组件:Spring Cloud Gateway可以与多种服务注册中心(如Eureka、Consul等)集成。这些集成是通过实现
DiscoveryClient
接口来完成的。DiscoveryClient
提供了获取服务实例信息的方法,例如getInstances(String serviceId)
。这使得Gateway可以获取到注册中心中所有服务的实例信息。 -
创建路由定义:
DiscoveryClientRouteDefinitionLocator
会将从DiscoveryClient
获取到的服务实例信息转换为RouteDefinition
对象。这些RouteDefinition
对象包含了路由的基本信息,如ID、URI、断言和过滤器等。通过这些信息,Gateway可以知道如何将请求路由到特定的服务实例。 -
路由规则更新:当注册中心中的服务实例发生变化时,
DiscoveryClientRouteDefinitionLocator
会自动更新路由规则。这是通过监听服务实例变化事件来实现的。当接收到服务实例变化事件后,DiscoveryClientRouteDefinitionLocator
会重新获取服务实例信息,并更新RouteDefinition
对象。这样,Gateway就能实时地感知到服务实例的变化,并相应地调整路由规则。 -
请求转发:当Gateway接收到一个请求时,它会根据
DiscoveryClientRouteDefinitionLocator
提供的路由定义匹配相应的路由规则。然后,Gateway会将请求转发到匹配的服务实例。这个转发过程是通过NettyRoutingFilter
完成的,它会根据RouteDefinition
中的URI信息转发请求。
核心源码
GatewayDiscoveryClientAutoConfiguration
我们可以看到 当 DiscoveryClient
存在并且 spring.cloud.gateway.discovery.locator.enabled
为 true
时,创建一个 DiscoveryClientRouteDefinitionLocator
Bean,允许 Spring Cloud Gateway 动态地从服务注册中心发现路由定义。
DiscoveryClientRouteDefinitionLocator
核心方法getRouteDefinitions
getRouteDefinitions
方法的主要目的是从 DiscoveryClient
获取服务实例信息并将其转换为路由定义。首先解析 includeExpression
和 urlExpression
,然后根据 includeExpression
创建一个用于判断服务实例是否需要被包含在路由定义中的 Predicate
。接着从 DiscoveryClient
获取所有服务实例信息,并转换为 RouteDefinition
。转换过程中会生成 PredicateDefinition
和 FilterDefinition
。最后返回一个包含所有路由定义的 Flux
对象。
@Override
public Flux<RouteDefinition> getRouteDefinitions() {// 创建一个 SpelExpressionParser 用于解析表达式SpelExpressionParser parser = new SpelExpressionParser();// 解析 includeExpression,用于判断服务实例是否需要被包含在路由定义中Expression includeExpr = parser.parseExpression(properties.getIncludeExpression());// 解析 urlExpression,用于生成服务实例对应的 URIExpression urlExpr = parser.parseExpression(properties.getUrlExpression());// 根据 includeExpression 创建一个 Predicate,用于判断服务实例是否需要被包含在路由定义中Predicate<ServiceInstance> includePredicate;if (properties.getIncludeExpression() == null || "true".equalsIgnoreCase(properties.getIncludeExpression())) {includePredicate = instance -> true;} else {includePredicate = instance -> {Boolean include = includeExpr.getValue(evalCtxt, instance, Boolean.class);if (include == null) {return false;}return include;};}// 从 DiscoveryClient 获取所有服务实例信息并转换为路由定义return Flux.fromIterable(discoveryClient.getServices()).map(discoveryClient::getInstances) // 获取每个服务的所有实例.filter(instances -> !instances.isEmpty()) // 过滤掉没有实例的服务.map(instances -> instances.get(0)) // 获取每个服务的第一个实例.filter(includePredicate) // 过滤掉不需要被包含在路由定义中的服务实例.map(instance -> { // 将服务实例转换为 RouteDefinitionString serviceId = instance.getServiceId();RouteDefinition routeDefinition = new RouteDefinition();routeDefinition.setId(this.routeIdPrefix + serviceId);// 获取服务实例对应的 URIString uri = urlExpr.getValue(evalCtxt, instance, String.class);routeDefinition.setUri(URI.create(uri));final ServiceInstance instanceForEval = new DelegatingServiceInstance(instance, properties);// 生成 PredicateDefinitionfor (PredicateDefinition original : this.properties.getPredicates()) {PredicateDefinition predicate = new PredicateDefinition();predicate.setName(original.getName());for (Map.Entry<String, String> entry : original.getArgs().entrySet()) {String value = getValueFromExpr(evalCtxt, parser, instanceForEval, entry);predicate.addArg(entry.getKey(), value);}routeDefinition.getPredicates().add(predicate);}// 生成 FilterDefinitionfor (FilterDefinition original : this.properties.getFilters()) {FilterDefinition filter = new FilterDefinition();filter.setName(original.getName());for (Map.Entry<String, String> entry : original.getArgs().entrySet()) {String value = getValueFromExpr(evalCtxt, parser, instanceForEval, entry);filter.addArg(entry.getKey(), value);}routeDefinition.getFilters().add(filter);}return routeDefinition;});
}
4. Gateway路由的核心组件
4.1 路由断言
路由断言(Route Predicates)是Spring Cloud Gateway中的一个核心概念,它负责匹配HTTP请求的属性,并决定是否将请求路由到特定的服务。
使用断言,可以基于许多不同的请求属性定义路由规则,包括:
- 请求路径:比如请求的URL。
- 请求方法:GET、POST等。
- 请求头:可以匹配特定的请求头字段和值。
- 查询参数:可以匹配URL的查询参数。
- Cookie:可以匹配特定的cookie。
断言的定义通常在Spring配置文件(如application.yaml)中,作为路由定义的一部分。每个断言都是一种谓词(Predicate),这是一个返回true或false的函数。
路由断言的示例:
spring:cloud:gateway:routes:- id: user_serviceuri: http://localhost:8080/userpredicates:- Path=/user/**- Method=GET- Header=X-Request-User, \d+
在这个例子中,定义了一个名为"user_service"的路由,其目标URI为"http://localhost:8080/user"。定义了三个断言:
- Path断言:只有当请求路径以"/user/"开头时,才会触发该路由。
- Method断言:只有当HTTP请求方法为GET时,才会触发该路由。
- Header断言:只有当请求头中存在名为"X-Request-User"的字段,并且其值为数字时,才会触发该路由。
只有当所有的断言都返回true时,该请求才会被路由到目标服务。否则,Spring Cloud Gateway将返回404错误。
组合并生效相当于并且的关系
在这个示例中,只有满足以下所有条件的请求才会路由到http://localhost:8080/:
- 请求路径以/api/开头
- 请求方法为GET
- 请求头中包含X-Request-Id,且其值为数字
- 查询参数中包含debug,并且其值为true
- Cookie中包含sessionId,并且其值不为空
spring:cloud:gateway:routes:- id: host_routeuri: http://localhost:8080/predicates:- Path=/api/**- Method=GET- Header=X-Request-Id, \d+- Query=debug, true- Cookie=sessionId, .+
如果要或的关系需要分配多个路由
如果想要以"或"的关系生效,需要定义多个路由。考虑到Spring Cloud Gateway的工作方式,一个请求只能被一个路由处理。这意味着谓词是以"与"的方式工作的,而不是"或"。如果想要一个请求被多个谓词处理,需要创建多个路由。每个路由有一个谓词,这样一个请求可以匹配多个路由。
在以下的配置中,如果请求路径以/api/开头, 或请求方法为GET, 或请求头中包含X-Request-Id且其值为数字, 或查询参数中包含debug且其值为true, 或Cookie中包含sessionId且其值不为空,任何一个条件满足,请求都会路由到http://localhost:8080/。
spring:cloud:gateway:routes:- id: host_route1uri: http://localhost:8080/predicates:- Path=/api/**- id: host_route2uri: http://localhost:8080/predicates:- Method=GET- id: host_route3uri: http://localhost:8080/predicates:- Header=X-Request-Id, \d+- id: host_route4uri: http://localhost:8080/predicates:- Query=debug, true- id: host_route5uri: http://localhost:8080/predicates:- Cookie=sessionId, .+
4.2 路由过滤器
Spring Cloud Gateway作为一个API网关,提供了很多功能,如路由转发、断路器、限流等。其中,路由过滤器是其核心功能之一,它允许我们在请求被路由之前或之后对请求进行处理。本文将详细介绍Spring Cloud Gateway的路由过滤器。
路由过滤器概念
路由过滤器是一个Java类,用于修改进入或退出网关的HTTP请求和响应。它包含两种类型的过滤器:
- Global Filter:全局过滤器,对所有路由请求生效。
- GatewayFilter:网关过滤器,只对特定路由请求生效。
Spring Cloud Gateway中的过滤器基于WebFilter
接口实现,并且实现了Ordered
接口来控制过滤器的执行顺序。过滤器可以在请求被路由之前(Pre过滤器)或之后(Post过滤器)进行处理。
路由过滤器工厂
Spring Cloud Gateway的过滤器是通过工厂创建的。这些工厂实现了GatewayFilterFactory
接口,这个接口包含两个方法:
apply(T config)
:将配置信息传递给过滤器,并创建过滤器实例。getConfigClass()
:返回过滤器所使用的配置类。
内置路由过滤器
Spring Cloud Gateway提供了许多内置过滤器,可以覆盖大部分基本功能。以下是一些常用的内置过滤器:
- AddRequestHeader:添加请求头。
- AddRequestParameter:添加请求参数。
- AddResponseHeader:添加响应头。
- PrefixPath:添加前缀路径。
- RewritePath:重写请求路径。
- Retry:重试。
- SetPath:设置请求路径。
- SetResponseHeader:设置响应头。
- StripPrefix:去掉前缀。
- Hystrix:使用Hystrix断路器。
自定义路由过滤器
除了内置过滤器以外,我们还可以自定义过滤器。自定义过滤器需要实现GatewayFilter
接口,并重写filter(ServerWebExchange exchange, GatewayFilterChain chain)
方法。下面是一个简单的自定义过滤器示例:
创建了一个名为 CustomGatewayFilterFactory
的类,实现了 GatewayFilterFactory<GatewayFilterFactory.Args>
接口,并重写了 apply
和 name
方法。在 apply
方法中,我们返回一个新的 CustomGatewayFilter
实例。在 name
方法中,我们返回过滤器的名称,这个名称需要与配置文件中的 filters
部分所引用的名称相匹配。最后,我们将 CustomGatewayFilterFactory
注册为一个 Bean。
public class CustomGatewayFilter implements GatewayFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 在请求被路由之前执行的逻辑System.out.println("Custom Gateway Filter Pre");return chain.filter(exchange).then(Mono.fromRunnable(() -> {// 在请求被路由之后执行的逻辑System.out.println("Custom Gateway Filter Post");}));}
}
要在配置文件中为特定路由配置 CustomGatewayFilter
,需要在 Spring Cloud Gateway 的配置文件(如 application.yml
或 application.properties
)中定义路由规则,并在 filters
部分引用的 CustomGatewayFilter
。以下是一个在 application.yml
中配置 CustomGatewayFilter
的示例:
spring:cloud:gateway:routes:- id: my_routeuri: http://example.com # 目标服务的地址predicates:- Path=/my_path/** # 路由条件,例如路径匹配filters:- name: CustomFilter # 在这里引用的自定义过滤器
需要先将 CustomGatewayFilter
注册为一个全局过滤器。为了达到这个目的,需要创建一个 GatewayFilterFactory
,并将其注册为一个 Bean。请参考以下示例:
@Configuration
public class CustomGatewayFilterConfiguration {@Beanpublic CustomGatewayFilterFactory customGatewayFilterFactory() {return new CustomGatewayFilterFactory();}public static class CustomGatewayFilterFactory implements GatewayFilterFactory<GatewayFilterFactory.Args> {@Overridepublic GatewayFilter apply(GatewayFilterFactory.Args args) {return new CustomGatewayFilter();}@Overridepublic String name() {return "CustomFilter";}}
}
5. 路由的动态刷新
我们写一个简化的教程来看下如何在Spring Cloud Gateway中实现动态路由刷新。
5.1. 添加依赖
在Gateway服务的pom.xml
文件中添加以下依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
这里我们使用RabbitMQ作为消息代理,如果想使用其他消息代理,请替换相应的依赖。
5.2. 配置application.yml
在Gateway服务的src/main/resources/application.yml
中添加以下配置:
spring:cloud:gateway:discovery:locator:enabled: trueroutes:- id: user-serviceuri: lb://user-servicepredicates:- Path=/user-service/**config:uri: http://localhost:8888rabbitmq:host: localhostport: 5672username: guestpassword: guestbus:id: ${spring.application.name}:${server.port}
这里我们配置了一个名为user-service
的路由,路由的配置信息将从Config Server(地址为http://localhost:8888
)获取。
5.3. 创建Config Server
创建一个新的Spring Boot项目,名为config-server
。在pom.xml
文件中添加以下依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-config-server</artifactId>
</dependency>
在src/main/resources/application.yml
中添加以下配置:
server:port: 8888
spring:cloud:config:server:git:uri: https://github.com/your-username/your-repo.git
这里配置了Config Server从远程Git仓库获取配置信息。
在src/main/java/com/example/configserver/ConfigServerApplication.java
中添加@EnableConfigServer
注解以启动Config Server:
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {public static void main(String[] args) {SpringApplication.run(ConfigServerApplication.class, args);}
}
启动Config Server。
5.4. 在远程Git仓库中添加配置文件
在的远程Git仓库中添加一个名为gateway-service.yml
的文件,内容如下:
spring:cloud:gateway:routes:- id: user-serviceuri: lb://user-servicepredicates:- Path=/user-service/**
这里配置了一个名为user-service
的路由。
5.5. 启动Gateway服务
现在启动的Gateway服务,它将从Config Server获取最新的路由信息。可以通过访问http://localhost:8080/user-service/some-api
来测试路由是否生效。
5.6. 动态刷新路由信息
当gateway-service.yml
文件发生变化并推送到远程Git仓库后,可以发送一个POST请求到http://localhost:8080/actuator/refresh
端点以刷新Gateway的路由信息。
也可以在config-server
项目中添加Spring Cloud Bus的依赖,并添加相应的配置,以实现自动广播路由变更消息。
6. 处理路由失败和异常
如何处理路由失败和异常也是大家在写一个高可用,健壮性良好的网关服务的基本要求。那么在本教程中,我们来了解一下Spring Cloud Gateway中如何处理路由失败和异常,以及如何配置回退和重试策略。
6.1 处理请求失败和异常
当路由转发过程中发生异常,例如目标服务不可用,可以使用Gateway的全局异常处理器来捕获异常并返回一个友好的错误响应。默认情况下,Gateway会使用org.springframework.cloud.gateway.handler.GlobalErrorWebExceptionHandler
作为全局异常处理器。可以通过实现ErrorWebExceptionHandler
接口并注册为Spring Bean来自定义全局异常处理器。
写一个简单的例子可供参考
自定义CustomGlobalExceptionHandler继承了AbstractErrorWebExceptionHandler
并覆盖了getRoutingFunction
方法,以自定义错误响应。
@Component
public class CustomGlobalExceptionHandler extends AbstractErrorWebExceptionHandler {public CustomGlobalExceptionHandler(ErrorAttributes errorAttributes,WebProperties.Resources resources,ApplicationContext applicationContext,ServerCodecConfigurer serverCodecConfigurer) {super(errorAttributes, resources, applicationContext);setMessageWriters(serverCodecConfigurer.getWriters());setMessageReaders(serverCodecConfigurer.getReaders());}@Overrideprotected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);}private Mono<ServerResponse> renderErrorResponse(ServerRequest request) {Throwable error = getError(request);// 自定义响应体Map<String, Object> errorAttributes = new HashMap<>();errorAttributes.put("message", error.getMessage());errorAttributes.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());errorAttributes.put("timestamp", LocalDateTime.now());return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(errorAttributes));}
}
默认实现是DefaultErrorWebExceptionHandler
6.2 配置回退和重试策略
使用Spring Cloud Gateway,可以为路由配置回退和重试策略。回退策略允许在转发请求失败时返回一个预定义的响应。重试策略允许在请求失败时尝试重新发送请求。
为了配置回退策略,可以在路由配置中添加fallbackUri
属性。
spring:cloud:gateway:routes:- id: user-serviceuri: lb://user-servicepredicates:- Path=/user-service/**filters:- name: Hystrixargs:name: user-servicefallbackUri: forward:/fallback
为user-service
路由配置了一个回退URI,它会将请求转发到/fallback
端点。需要在的Gateway服务中实现这个端点,并返回一个预定义的响应。
为了配置重试策略,可以在路由配置中添加Retry
过滤器。
为user-service
路由配置了一个重试策略。当请求方法为GET
且服务器返回500 Internal Server Error
状态时,Gateway会尝试重新发送请求,最多重试3次。
spring:cloud:gateway:routes:- id: user-serviceuri: lb://user-servicepredicates:- Path=/user-service/**filters:- name: Retryargs:retries: 3statuses: INTERNAL_SERVER_ERRORmethods: GET
7. 高级路由功能
写不动了,路由详解就到这儿,后面有时间补充一下高级路由功能。
- 7.1 如何配置负载均衡
- 7.2 如何配置熔断器
- 7.3 如何配置速率限制
8. 参考文档
Spring Cloud Gateway官方文档 https://cloud.spring.io/spring-cloud-gateway/2.0.x/single/spring-cloud-gateway.html
相关文章:

Spring Cloud Gateway2之路由详解
Spring Cloud Gateway路由 文章目录 1. 前言2. Gateway路由的基本概念3. 三种路由1. 静态路由2. 动态路由1. 利用外部存储2. API动态路由 3. 服务发现路由(自动路由)3.1. 配置方式3.2 自动路由(服务发现)原理核心源码GatewayDiscoveryClientAutoConfigur…...

阿里云RDS关系型数据库详细介绍_多版本数据库说明
阿里云RDS关系型数据库大全,关系型数据库包括MySQL版、PolarDB、PostgreSQL、SQL Server和MariaDB等,NoSQL数据库如Redis、Tair、Lindorm和MongoDB,阿里云百科分享阿里云RDS关系型数据库大全: 目录 阿里云RDS关系型数据库大全 …...

Vue中的数据绑定
一、v-bind单向数据绑定 单向数据绑定中,数据只能由data流向页面。 v-bind:属性名"data变量" 或简写为 :属性名"data变量" 我们修改data中的iptvalue值,页面input框中的value值改变。 而我们修改input框中的value值࿰…...

前后端分离计算机毕设项目之基于SpringBoot的旅游网站的设计与实现《内含源码+文档+部署教程》
博主介绍:✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业毕业设计项目实战6年之久,选择我们就是选择放心、选择安心毕业✌ 🍅由于篇幅限制,想要获取完整文章或者源码,或者代做&am…...
[JAVAee]Spring拦截器
适用场景 像是页面的登录验证处理,权限校验,登录日志的处理. 实现步骤 创建⾃定义拦截器,实现 HandlerInterceptor 接⼝的 preHandle(执⾏具体⽅法之前的预处理⽅法.将⾃定义拦截器加⼊ WebMvcConfigurer 的 addInterceptors ⽅法中. 下面以登录验证为例,实现拦…...

【nvm】Node Version Manager(NVM)安装配置以及使用(WIN版)
NVM 包管理工具 安装 访问NVM-Windows的GitHub页面:点击nvm-setup.exe。 根据提示进行下一步,文件位置选择自定义位置 验证安装是否成功 nvm version 。如果成功,它将显示NVM的版本号。 使用 nvm list available查看所有的可以被下载…...

【微服务】七. http客户端Feign
7.1 基于Feign远程调用 RestTimeplate方式调用存在的问题 先来看以前利用RestTemplate发起远程调用的代码: String url "http://userservice/user"order.getUserId(); User user restTemplate.getForObject(url,User.class);存在下面的问题…...

【Spring Boot 源码学习】OnWebApplicationCondition 详解
Spring Boot 源码学习系列 OnWebApplicationCondition 详解 引言往期内容主要内容1. getOutcomes 方法2. getMatchOutcome 方法3. isWebApplication 方法3.1 isServletWebApplication 方法3.2 isReactiveWebApplication 方法3.3 isAnyWebApplication 方法 总结 引言 上篇博文带…...
力扣之二分法
今天,学习了二分法,详细内容见代码随想录 (programmercarl.com),讲得十分好。 力扣之35. 搜索插入位置 - 力扣(LeetCode)。 class Solution { public:int searchInsert(vector<int>& nums, int target) {in…...

css图形化理解--扭曲函数skew()
transform: skewX(30deg);transform: skewY(45deg);transform: skew(30deg,45deg);transform: skewX(angleX);transform: skewY(angleY);transform: skew(angleX,angleY); 是CSS中的一个2D变换方法,它用于对元素沿X轴、Y轴进行倾斜变换。其中,angle表示倾…...

八、互联网技术——物联网
文章目录 一、智慧物联案例分析二、M2M技术三、数据保护综合案例分析一、智慧物联案例分析 智能物流是一种典型的物联网应用。一个物流仓储管理系统架构如下图所示: [问题1] 图中的三层功能:仓库物品识别、网络接入、物流管理中心,分别可对应到物联网基本架构中的哪一层? …...

聊聊MySQL的聚簇索引和非聚簇索引
文章目录 1. 索引的分类1. 存储结构维度2. 功能维度3. 列数维度4. 存储方式维度5. 更新方式维度 2. 聚簇索引2.1 什么是聚簇索引2.2 聚簇索引的工作原理 3. 非聚簇索引(MySQL官方文档称为Secondary Indexes)3.1 什么是非聚簇索引3.2 非聚簇索引的工作原理…...
python之subprocess模块详解
介绍 subprocess是Python 2.4中新增的一个模块,它允许你生成新的进程,连接到它们的 input/output/error 管道,并获取它们的返回(状态)码。 这个模块的目的在于替换几个旧的模块和方法。 那么我们到底该用哪个模块、哪个…...
第10讲:Vue组件的定义与注册
定义组件 1. 在程序的 components 目录下新建一个名为 Child.vue 的文件 2. 在文件内键入如下代码 <template><div>Child</div> </template> <script> export default {name: Child } </script>新建的 Child .vue 文件即为我们定义的组件…...

Pycharm操作git仓库 合并等
菜单 Git CommitPushUpdate ProjectPullFetchMergreRebase 查询 查询分支 查询本地所有分支 # 查询本地分支 git branch# 查询远程分支 git branch -rPycharm查看当前分支 步骤: Git->Branches 哈喽,大家好,我是[有勇气的牛排]&…...

Flink+Doris 实时数仓
Flink+Doris 实时数仓 Doris基本原理 Doris基本架构非常简单,只有FE(Frontend)、BE(Backend)两种角色,不依赖任何外部组件,对部署和运维非常友好。架构图如下 可以 看到Doris 的数仓架构十分简洁,不依赖 Hadoop 生态组件,构建及运维成本较低。 FE(Frontend)以 Java 语…...

windows 任务计划自动提交 笔记到github 、gitee
一、必须有个git仓库托管到git上。 这个就不用说了,自己在github或者码云上新建一个仓库就行了。 二、创建自动提交脚本 这个bat脚本是在windows环境下使用的。 注意:windows定时任务下 调用自动提交git前,必须先进入该git仓库目录&#x…...
闭包和装饰器
#闭包的作用 #全局变量有被修改的风险,代码在命名空间上不够干净整洁 #第一种,不使用闭包的场景 account_amount0 def atm(num,depositTrue):global account_amountif deposit:account_amountnumprint(f"存款:{num},账户余额…...
注册器模式
注册器模式 注册器模式(Registry Pattern)是一种设计模式,用于管理和维护对象的注册和检索。它允许您在运行时注册对象,并通过一个唯一的标识符或名称来检索这些对象。这种模式通常用于构建可扩展的、松耦合的系统,其…...

5SpringMVC处理Ajax请求携带的JSON格式(“key“:value)的请求参数
SpringMVC处理Ajax 参考文章数据交换的常见格式,如JSON格式和XML格式 请求参数的携带方式 浏览器发送到服务器的请求参数有namevalue&...(键值对)和{key:value,...}(json对象)两种格式 URL请求会将请求参数以键值对的格式拼接到请求地址后面,form表单的GET和POST请求会…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...

DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...