Spring 官方最终仍是按捺不住推出了本身的网关组件:Spring Cloud Gateway ,相比以前咱们使用的 Zuul(1.x) 它有哪些优点呢?Zuul(1.x) 基于 Servlet,使用阻塞 API,它不支持任何长链接,如 WebSockets,Spring Cloud Gateway 使用非阻塞 API,支持 WebSockets,支持限流等新特性。java
Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。web
Spring Cloud Gateway 做为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不只提供统一的路由方式,而且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。正则表达式
相关概念:spring
org.springframework.cloud.gateway.filter.GatewayFilter
的实例,咱们可使用它修改请求和响应。工做流程:浏览器
客户端向 Spring Cloud Gateway 发出请求。若是 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再经过指定的过滤器链来将请求发送到咱们实际的服务执行业务逻辑,而后返回。 过滤器之间用虚线分开是由于过滤器可能会在发送代理请求以前(“pre”)或以后(“post”)执行业务逻辑。安全
Spring Cloud Gateway 的特征:cookie
Spring Cloud Gateway 网关路由有两种配置方式:架构
@Bean
自定义 RouteLocator,在启动主类 Application 中配置这两种方式是等价的,建议使用 yml 方式进配置。app
使用 Spring Cloud Finchley 版本,Finchley 版本依赖于 Spring Boot 2.0.6.RELEASE。curl
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
经测试 Finchley.RELEASE 有 bug 屡次请求会报空指针异常,SR2 是 Spring Cloud 的最新版本。
添加项目须要使用的依赖包
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
Spring Cloud Gateway 是使用 netty+webflux 实现所以不须要再引入 web 模块。
咱们先来测试一个最简单的请求转发。
server:
port: 8080
spring:
cloud:
gateway:
routes:
- id: neo_route
uri: http://www.ityouknow.com
predicates:
- Path=/spring-cloud
各字段含义以下:
上面这段配置的意思是,配置了一个 id 为 neo_route 的路由规则,当访问地址 http://localhost:8080/spring-cloud
时会自动转发到地址:http://www.ityouknow.com/spring-cloud
。配置完成启动项目便可在浏览器访问进行测试,当咱们访问地址http://localhost:8080/spring-cloud
时会展现页面展现以下:
证实页面转发成功。
转发功能一样能够经过代码来实现,咱们能够在启动类 GateWayApplication 中添加方法 customRouteLocator()
来定制转发规则。
@SpringBootApplication public class GateWayApplication { public static void main(String[] args) { SpringApplication.run(GateWayApplication.class, args); } @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route("path_route", r -> r.path("/about") .uri("http://ityouknow.com")) .build(); } }
上面配置了一个 id 为 path_route 的路由,当访问地址http://localhost:8080/about
时会自动转发到地址:http://www.ityouknow.com/about
和上面的转发效果同样,只是这里转发的是以项目地址/about
格式的请求地址。
上面两个示例中 uri 都是指向了个人我的网站,在实际项目使用中能够将 uri 指向对外提供服务的项目地址,统一对外输出接口。
以上即是 Spring Cloud Gateway 最简单的两个请求示例,Spring Cloud Gateway 还有更多实用的功能接下来咱们一一介绍。
Spring Cloud Gateway 的功能很强大,咱们仅仅经过 Predicates 的设计就能够看出来,前面咱们只是使用了 predicates 进行了简单的条件匹配,其实 Spring Cloud Gataway 帮咱们内置了不少 Predicates 功能。
Spring Cloud Gateway 是经过 Spring WebFlux 的 HandlerMapping
作为底层支持来匹配到转发路由,Spring Cloud Gateway 内置了不少 Predicates 工厂,这些 Predicates 工厂经过不一样的 HTTP 请求参数来匹配,多个 Predicates 工厂能够组合使用。
Predicate 来源于 Java 8,是 Java 8 中引入的一个函数,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其余复杂的逻辑(好比:与,或,非)。能够用于接口请求参数校验、判断新老数据是否有变化须要进行更新操做。
在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性实现了各类路由匹配规则,有经过 Header、请求参数等不一样的条件来进行做为条件匹配到对应的路由。网上有一张图总结了 Spring Cloud 内置的几种 Predicate 的实现。
说白了 Predicate 就是为了实现一组匹配规则,方便让请求过来找到对应的 Route 进行处理,接下来咱们接下 Spring Cloud GateWay 内置几种 Predicate 的使用。
Predicate 支持设置一个时间,在请求进行转发的时候,能够经过判断在这个时间以前或者以后进行转发。好比咱们如今设置只有在2019年1月1日才会转发到个人网站,在这以前不进行转发,我就能够这样配置:
spring:
cloud:
gateway:
routes:
- id: time_route
uri: http://ityouknow.com
predicates:
- After=2018-01-20T06:06:06+08:00[Asia/Shanghai]
Spring 是经过 ZonedDateTime 来对时间进行的对比,ZonedDateTime 是 Java 8 中日期时间功能里,用于表示带时区的日期与时间信息的类,ZonedDateTime 支持经过时区来设置时间,中国的时区是:Asia/Shanghai
。
After Route Predicate 是指在这个时间以后的请求都转发到目标地址。上面的示例是指,请求时间在 2018年1月20日6点6分6秒以后的全部请求都转发到地址http://ityouknow.com
。+08:00
是指时间和UTC时间相差八个小时,时间地区为Asia/Shanghai
。
添加完路由规则以后,访问地址http://localhost:8080
会自动转发到http://ityouknow.com
。
Before Route Predicate 恰好相反,在某个时间以前的请求的请求都进行转发。咱们把上面路由规则中的 After 改成 Before,以下:
spring:
cloud:
gateway:
routes:
- id: after_route
uri: http://ityouknow.com
predicates:
- Before=2018-01-20T06:06:06+08:00[Asia/Shanghai]
就表示在这个时间以前能够进行路由,在这时间以后中止路由,修改完以后重启项目再次访问地址http://localhost:8080
,页面会报 404 没有找到地址。
除过在时间以前或者以后外,Gateway 还支持限制路由请求在某一个时间段范围内,可使用 Between Route Predicate 来实现。
spring:
cloud:
gateway:
routes:
- id: after_route
uri: http://ityouknow.com
predicates:
- Between=2018-01-20T06:06:06+08:00[Asia/Shanghai], 2019-01-20T06:06:06+08:00[Asia/Shanghai]
这样设置就意味着在这个时间段内能够匹配到此路由,超过这个时间段范围则不会进行匹配。经过时间匹配路由的功能很酷,能够用在限时抢购的一些场景中。
Cookie Route Predicate 能够接收两个参数,一个是 Cookie name ,一个是正则表达式,路由规则会经过获取对应的 Cookie name 值和正则表达式去匹配,若是匹配上就会执行路由,若是没有匹配上则不执行。
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: http://ityouknow.com
predicates:
- Cookie=ityouknow, kee.e
使用 curl 测试,命令行输入:
curl http://localhost:8080 --cookie "ityouknow=kee.e"
则会返回页面代码,若是去掉--cookie "ityouknow=kee.e"
,后台汇报 404 错误。
Header Route Predicate 和 Cookie Route Predicate 同样,也是接收 2 个参数,一个 header 中属性名称和一个正则表达式,这个属性值和正则表达式匹配则执行。
spring:
cloud:
gateway:
routes:
- id: header_route
uri: http://ityouknow.com
predicates:
- Header=X-Request-Id, \d+
使用 curl 测试,命令行输入:
curl http://localhost:8080 -H "X-Request-Id:666666"
则返回页面代码证实匹配成功。将参数-H "X-Request-Id:666666"
改成-H "X-Request-Id:neo"
再次执行时返回404证实没有匹配。
Host Route Predicate 接收一组参数,一组匹配的域名列表,这个模板是一个 ant 分隔的模板,用.
号做为分隔符。它经过参数中的主机地址做为匹配规则。
spring:
cloud:
gateway:
routes:
- id: host_route
uri: http://ityouknow.com
predicates:
- Host=**.ityouknow.com
使用 curl 测试,命令行输入:
curl http://localhost:8080 -H "Host: www.ityouknow.com"
curl http://localhost:8080 -H "Host: md.ityouknow.com"
经测试以上两种 host 都可匹配到 host_route 路由,去掉 host 参数则会报 404 错误。
能够经过是 POST、GET、PUT、DELETE 等不一样的请求方式来进行路由。
spring:
cloud:
gateway:
routes:
- id: method_route
uri: http://ityouknow.com
predicates:
- Method=GET
使用 curl 测试,命令行输入:
# curl 默认是以 GET 的方式去请求
curl http://localhost:8080
测试返回页面代码,证实匹配到路由,咱们再以 POST 的方式请求测试。
# curl 默认是以 GET 的方式去请求
curl -X POST http://localhost:8080
返回 404 没有找到,证实没有匹配上路由
Path Route Predicate 接收一个匹配路径的参数来判断是否走路由。
spring:
cloud:
gateway:
routes:
- id: host_route
uri: http://ityouknow.com
predicates:
- Path=/foo/{segment}
若是请求路径符合要求,则此路由将匹配,例如:/foo/1 或者 /foo/bar。
使用 curl 测试,命令行输入:
curl http://localhost:8080/foo/1
curl http://localhost:8080/foo/xx
curl http://localhost:8080/boo/xx
通过测试第一和第二条命令能够正常获取到页面返回值,最后一个命令报404,证实路由是经过指定路由来匹配。
Query Route Predicate 支持传入两个参数,一个是属性名一个为属性值,属性值能够是正则表达式。
spring:
cloud:
gateway:
routes:
- id: query_route
uri: http://ityouknow.com
predicates:
- Query=smile
这样配置,只要请求中包含 smile 属性的参数便可匹配路由。
使用 curl 测试,命令行输入:
curl localhost:8080?smile=x&id=2
通过测试发现只要请求汇总带有 smile 参数即会匹配路由,不带 smile 参数则不会匹配。
还能够将 Query 的值以键值对的方式进行配置,这样在请求过来时会对属性值和正则进行匹配,匹配上才会走路由。
spring:
cloud:
gateway:
routes:
- id: query_route
uri: http://ityouknow.com
predicates:
- Query=keep, pu.
这样只要当请求中包含 keep 属性而且参数值是以 pu 开头的长度为三位的字符串才会进行匹配和路由。
使用 curl 测试,命令行输入:
curl localhost:8080?keep=pub
测试能够返回页面代码,将 keep 的属性值改成 pubx 再次访问就会报 404,证实路由须要匹配正则表达式才会进行路由。
Predicate 也支持经过设置某个 ip 区间号段的请求才会路由,RemoteAddr Route Predicate 接受 cidr 符号(IPv4 或 IPv6 )字符串的列表(最小大小为1),例如 192.168.0.1/16 (其中 192.168.0.1 是 IP 地址,16 是子网掩码)。
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: http://ityouknow.com
predicates:
- RemoteAddr=192.168.1.1/24
能够将此地址设置为本机的 ip 地址进行测试。
curl localhost:8080
果请求的远程地址是 192.168.1.10,则此路由将匹配。
上面为了演示各个 Predicate 的使用,咱们是单个单个进行配置测试,其实能够将各类 Predicate 组合起来一块儿使用。
例如:
spring:
cloud:
gateway:
routes:
- id: host_foo_path_headers_to_httpbin
uri: http://ityouknow.com
predicates:
- Host=**.foo.org
- Path=/headers
- Method=GET
- Header=X-Request-Id, \d+
- Query=foo, ba.
- Query=baz
- Cookie=chocolate, ch.p
- After=2018-01-20T06:06:06+08:00[Asia/Shanghai]
各类 Predicates 同时存在于同一个路由时,请求必须同时知足全部的条件才被这个路由匹配。
一个请求知足多个路由的谓词条件时,请求只会被首个成功匹配的路由转发