关于springcloud gateway的介绍闲言少叙,直接上手
快速上手 使用spring cloud gateway非常容易上手,在全面学习之前,我们先来看一个简单的小例子。
创建一个spring boot项目 使用spring initializr创建一个spring boot项目,选择webflux和gateway的依赖。
编写一个简单的路由 在application.yml中添加如下配置:
1 2 3 4 5 6 7 8 spring: cloud: gateway: routes: - id: path_route predicates: - Path=/get uri: http://www.baidu.com
通过这个简单的配置文件,可以看出spring cloud gateway是由一些列route组成的
route路由是Spring Cloud Gateway的基本模块,它由一个ID、一个目标URI、一系列的断言和一系列的过滤器组成。
上面这个配置的含义通过断言对路径是/get的请求,转发到uri http://www.baidu.com。
启动项目 启动项目,访问[http://localhost:8080/get,可以看到页面加载了百度首页。
基本流程 熟悉Spring Cloud gateway要解决的问题和基本流程,才能让我们更好的学习它。spring cloud gateway的基本流程如下图所示:
当客户端发送请求到Spring Cloud Gateway时,spring gateway会根据请求的信息和路由规则匹配相应的Gateway Web Handler。Handler会通过一个filter的链路来对请求进行处理,filter可以在request代理发送前或者发送后进行数据处理。
核心概念 路由 路由是Spring Cloud Gateway的基本模块,它由一个ID、一个目标URI、一系列的断言和一系列的过滤器组成。 当一个请求进入Spring Cloud Gateway时,系统会按照顺序去试着匹配所有的路由,当匹配成功时,就会执行相应的过滤器链。然后转发给目标URI。
实际上使用Spring Cloud Gateway时,我们主要的工作就是指定路由规则。也就是指定路由的ID、目标URI、断言和过滤器。指定路由规则的方式有两种,一种是在配置文件中指定,另一种是通过编码的方式指定。
配置文件指定路由规则 在application.yml中添加如下配置:
1 2 3 4 5 6 7 8 9 10 11 12 spring: cloud: gateway: routes: - id: path_route uri: http://www.baidu.com predicates: - Path=/get - id: host_route uri: http://www.baidu.com predicates: - Host=**.baidu.com
编码指定路由规则 在Spring Cloud Gateway中,我们可以通过编码的方式去指定路由规则,这种方式更加灵活,我们可以在运行时动态的添加、删除路由规则。
1 2 3 4 5 6 7 8 9 10 11 12 13 @Configuration public class GatewayConfig { @Bean public RouteLocator customRouteLocator (RouteLocatorBuilder builder) { return builder.routes() .route("path_route" , r -> r.path("/get" ) .uri("http://www.baidu.com" )) .route("host_route" , r -> r.host("*.baidu.com" ) .uri("http://www.baidu.com" )) .build(); } }
无论是哪种方式,在路由的配置中,我们基本上需要做的就是指定断言、设定过滤器、指定跳转或者处理的handler。 下面我们就一一了解下这些概念。
断言 断言是一个布尔表达式,它的作用是判断请求是否满足路由的条件。 如果断言为true,则匹配该路由,否则不匹配。 断言可以通过配置文件或者编码的方式去指定。
配置文件指定断言 在配置文件中指定断言又有两种方式,一种是快捷方式实现,一种是全量方式实现。
快捷方式实现 1 2 3 4 5 6 7 8 spring: cloud: gateway: routes: - id: after_route uri: https://example.org predicates: - Cookie=mycookie,mycookievalue
全量方式实现 1 2 3 4 5 6 7 8 9 10 11 spring: cloud: gateway: routes: - id: after_route uri: https://example.org predicates: - name: Cookie args: name: mycookie regexp: mycookievalue
通过上述两种方式,我们可以看到:快捷方式通过逗号分隔的方式去指定断言的名称和参数,全量方式通过name和args两个属性去指定断言的名称和参数。
编码指定断言 在编码中指定断言,我们可以通过PredicateSpec的方法去指定断言,如下:
1 2 3 4 5 6 7 8 9 10 11 @Configuration public class GatewayConfig { @Bean public RouteLocator customRouteLocator (RouteLocatorBuilder builder) { return builder.routes() .route("path_route" , r -> r.path("/get" ).uri("http://www.baidu.com" )) .route("host_route" , r -> r.host("*.baidu.com" ).uri("http://www.baidu.com" )) .build(); } }
在上述例子中,我们通过编码的方式去指定了两个路由规则,分别是path_route和host_route。我们通过编码的方式去设定断言、过滤器和目标URI。
断言中的segment 在断言中可以使用segment进行占位。并且segment代表的值,可以作为变量用在下面会提到的GatewayFilter中。
举个例子。
1 2 3 4 5 6 7 8 9 10 spring: cloud: gateway: routes: - id: path_route uri: https://example.org predicates: - Path=/red/{segment},/blue/{segment} filters: - AddRequestHeader=X-Request-Red, Blue-{segment}
这个断言可以接收/red/1 或者/red/1/或者/red/blue或者/blue/green
如果matchTrailingSlash设置为false,/red/1/这种最后带/的就不能接收。matchTrailingSlash默认是true。
断言的总结 当你理解了断言的意图及配置方式后,使用断言就变得非常简单。一些常用的内置的断言工厂,你可以通过官网去学习他们的使用方法。
过滤器 过滤器是Spring Cloud Gateway的核心组件,它的作用是在请求被路由之前或之后对请求进行修改。Spring Cloud Gateway的过滤器分为两种类型:GatewayFilter和GlobalFilter
GlobalFilter:全局过滤器,可以在请求被路由之前或之后对请求进行修改。
GatewayFilter:作用于单个路由的局部过滤器,可以在请求被路由之前或之后对请求进行修改。
全局过滤器 全局过滤器是作用于所有路由的过滤器,可以在请求被路由之前或之后对请求进行修改。Spring Gateway内置了一些全局过滤器。除了内置的常用全局过滤器以外,我们还可以自定义全局过滤器。关于内置的全局过滤器,你可以通过官网去一一了解,或者有用到全局过滤器的时候先去官网查找。如果没有合适的再考虑自定义过滤器。
配置文件指定全局过滤器 1 2 3 4 5 6 7 8 spring: cloud: gateway: globalfilters: - name: AddRequestHeader args: name: X-Request-Global-Foo value: Global-Bar
编码指定全局过滤器 1 2 3 4 5 6 7 8 9 10 @Configuration public class GatewayConfig { @Bean public GlobalFilter customGlobalFilter () { return (exchange, chain) -> { ServerHttpRequest request = exchange.getRequest().mutate().header("X-Request-Global-Foo" , "Global-Bar" ).build(); return chain.filter(exchange.mutate().request(request).build()); }; } }
自定义全局过滤器 自定义过滤器需要实现GatewayFilter接口,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Component public class MyGlobalFilter implements GlobalFilter , Ordered { @Override public Mono<Void> filter (ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("global filter" ); return chain.filter(exchange); } @Override public int getOrder () { return 0 ; } }
在实际的使用中可以根据自己的业务需求去使用或者组合使用合适的过滤器。
局部过滤器 局部过滤器是作用于单个路由的过滤器,可以在请求被路由之前或之后对请求进行修改。Spring Gateway内置了一些局部过滤器。除了内置的常用局部过滤器以外,我们还可以自定义局部过滤器。 关于内置的全局过滤器,你可以通过官网去一一了解,或者有用到全局过滤器的时候先去官网查找。如果没有合适的再考虑自定义过滤器。
配置文件中配置局部过滤器 在配置文件中,定义的Router中,我们通过Filters来指定过滤器。在Filters中,我们可以指定多个过滤器,过滤器的执行顺序是按照Filters中的顺序来执行的。在每个过滤器中,我们通过Name和Args来指定过滤器的名称和参数。或者我们可以通过 Name =Args的方式来设定过滤器。
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 spring: cloud: gateway: routes: - id: path_route uri: http://www.baidu.com predicates: - Path=/get filters: - AddRequestHeader=X-Request-Foo, Bar - AddResponseHeader=X-Response-Foo, Bar - DedupeResponseHeader=Foo - Hystrix=fooCommand - PrefixPath=/httpbin - PreserveHostHeader - RemoveRequestHeader=Foo - RemoveResponseHeader=Foo - RewritePath=/foo/(?<segment>.*), /$\{segment} - RewriteResponseHeader=Location, http://newlocation.org - RequestRateLimiter=5, 1 , SECONDS - Retry=3 - SaveSession - SecureHeaders - SetPath=/foo/{segment} - SetRequestHeader=X-Request-Foo, Bar - SetResponseHeader=X-Response-Foo, Bar - SetStatus=401 - StripPrefix=1 - StripRequestHeader=Foo - StripResponseHeader=Foo - Weight=foo, 5
编码使用局部过滤器 在编码中,我们可以通过Filters来指定过滤器。在Filters中,我们可以指定多个过滤器,过滤器的执行顺序是按照Filters中的顺序来执行的。
1 2 3 4 5 6 7 8 9 10 11 12 13 @Configuration public class GatewayConfig { @Bean public RouteLocator customRouteLocator (RouteLocatorBuilder builder) { return builder.routes() .route("path_route" , r -> r.path("/get" ) .filters(f -> f.addRequestHeader("X-Request-Foo" , "Bar" ) .addResponseHeader("X-Response-Foo" , "Bar" )) .uri("http://www.baidu.com" )) .build(); } }
自定义局部过滤器 自定义过滤器需要实现GatewayFilter接口,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Component public class MyGatewayFilter implements GatewayFilter , Ordered { @Override public Mono<Void> filter (ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("gateway filter" ); return chain.filter(exchange); } @Override public int getOrder () { return 0 ; } }
Handler Function 通过配置断言和过滤器,可以让Spring Cloud Gateway将请求路由到指定的服务上。但是,如果我们想要在Spring Cloud Gateway中直接处理请求,而不是将请求路由到指定的服务上,那么我们就需要使用Handler Function。
Handler Function是WebFlux中的一个概念,它是一个函数,它接收一个ServerRequest对象,返回一个Mono对象。在Spring Cloud Gateway中,我们可以通过Handler Function来处理请求,而不是将请求路由到指定的服务上。
自定义一个Handler Function 自定义一个Handler Function需要实现HandlerFunction接口,如下:
1 2 3 4 5 6 7 8 @Component public class MyHandlerFunction implements HandlerFunction <ServerResponse> { @Override public Mono<ServerResponse> handle (ServerRequest request) { return ServerResponse.ok().body(BodyInserters.fromObject("hello world" )); } }
使用Handler Function 1 2 3 4 5 6 7 8 9 10 11 import org.springframework.beans.factory.annotation.Autowired;@Configuration public class GatewayConfig { @Autowired private MyHandlerFunction myHandlerFunction; @Bean public RouterFunction<ServerResponse> htmlRouterFunction () { return RouterFunctions.route(RequestPredicates.path("/fallback" ), myHandlerFunction)); } }
总结 Spring Cloud Gateway在微服务中使用相当的简单方便。大多数使用,我们只需要配置Spring Cloud Gateway连接到注册中心,然后配置路由规则即可。甚至很多时候,路由配置都不需要设计,他会默认把请求和注册中心的服务进行匹配,如果匹配到,就会自动路由到对应的服务上。