介绍
Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
特点
- 动态路由
- Predicates 和 Filters 作用于特定路由
- 集成 Hystrix 断路器
- 集成 Spring Cloud DiscoveryClient
- 易于编写的 Predicates 和 Filters
- 限流
- 路径重写
相关概念
- Route(路由):这是网关的基本构建块。他由一个ID,一个目标URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配。
- Predicate(断言):这是一个Java8的Predicate。输入类型是一个ServerWebExchange。我们可以使用它来匹配来自Http请求,例如headers或参数。
- Filter(过滤器):这是org.springframework.cloud.gateway.filter.GatewayFilter的实例,我们可以使用它修改请求和响应。
工作流程
客户端发送一个请求到Spring Cloud Gateway,如果这个Gateway Handler Mapping中找到与请求匹配的路由,那么将其发送到Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
简单使用
创建一个Springboot项目。
1.依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
Spring Cloud Gateway 是使用 netty+webflux 实现因此不需要再引入 web 模块。
2.两种方式
- 编码式:
@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("pikachues_route", r -> r.path("/get")
.uri("http://httpbin.org"))
.build();
}
}
- yml配置
server:
port: 8080
spring:
cloud:
gateway:
routes:
- id: pikachues_router
uri: http://httpbin.org
predicates:
- Path=/get
各字段含义:
- id 路由名称,识别路由的唯一标识码。
- uri:目标服务地址
- predicates:路由条件,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。
- filters:过滤规则,本示例暂时没用。
选择任意一种配置,启动项目访问:http://localhost:8080/get,因为get与代码中定义的路径匹配,所以请求会被转发给http://httpbin.org进行处理。
Predicate(断言)
Predicate 来源于 Java 8,是 Java 8 中引入的一个函数,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。可以用于接口请求参数校验、判断新老数据是否有变化需要进行更新操作。
在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性实现了各种路由匹配规则,有通过 Header、请求参数等不同的条件来进行作为条件匹配到对应的路由。
说白了 Predicate 就是为了实现一组匹配规则,方便让请求过来找到对应的 Route 进行处理。
通过时间匹配
- id: time_router
uri: https://www.csdn.net/
predicates:
- After=2020-01-20T06:06:06+08:00[Asia/Shanghai]
Spring 是通过 ZonedDateTime 来对时间进行的对比,ZonedDateTime 是 Java 8 中日期时间功能里,用于表示带时区的日期与时间信息的类,ZonedDateTime 支持通过时区来设置时间,中国的时区是:Asia/Shanghai。
After Route Predicate 是指在这个时间之后的请求都转发到目标地址。上面的示例是指,请求时间在 2020年1月20日6点6分6秒之后的所有请求都转发到地址https://www.csdn.net/。+08:00是指时间和UTC时间相差八个小时,时间地区为Asia/Shanghai。
重启项目,访问地址http://localhost:8080会自动转发到https://www.csdn.net;
除了After之外还有两个关键字
- Before 表示在某个时间之前进行转发
- Between 表示在某个时间之间进行转发,两个时间用逗号隔开
通过请求方式匹配
可以通过是 POST、GET、PUT、DELETE 等不同的请求方式来进行路由。
- id: method_router
uri: https://www.csdn.net/
predicates:
- Method=get
配置完成后重启项目,访问地址http://localhost:8080,可以正常访问,当修改Method=post时不能正常访问。
通过请求路径匹配
- id: path_route
uri: https://www.csdn.net/
predicates:
- Path=/csdn/{segment}
{segment}表示后面跟一个参数,segment不唯一,也可以为其他名称,测试地址:http://localhost:8080/csdn/1
通过请求参数匹配
- id: query_route
uri: https://example.org
predicates:
- Query=name
以上配置,只要请求中包含 name属性的参数即可匹配路由。测试地址:http://localhost:8080/?name=pikachues&id=1
- 除了可以指定参数外还可以指定参数的值(参数值用正则表达式匹配)
- id: query_route
uri: https://example.org
predicates:
- Query=name,p.*
以上配置表示,请求中需要包含name属性,并且属性值必须以p开头的才能被匹配。测试地址:http://localhost:8080/?name=pikachues
通过请求ip匹配
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.124.1/24
通过请求Host匹配
通过请求Cookie匹配
通过请求Header匹配
Filter
简单介绍
Spring Cloud Gateway 的 Filter 的生命周期不像 Zuul 的那么丰富,它只有两个:“pre” 和 “post”。
- PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
- POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。Spring Cloud Gateway 的 Filter 分为两种:GatewayFilter 与 GlobalFilter。GlobalFilter 会应用到所有的路由上,而 GatewayFilter 将应用到单个路由或者一个分组的路由上。
上面的例子都是单个项目,下面结合eureka注册中心来测试Filter
将gateway注册到服务中心
1.添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.application.yml
server:
port: 8080
eureka:
client:
service-url:
defaultZone: http://localhost:1111/eureka
spring:
application:
name: gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启自动代理
logging:
level:
org.springframework.cloud.gateway: debug
spring.cloud.gateway.discovery.locator.enabled:是否与服务注册于发现组件进行结合,通过 serviceId 转发到具体的服务实例。默认为 false,设为 true 便开启通过服务中心的自动根据 serviceId 创建路由的功能。
3.启动测试
分别启动项目eureka-server、eureka-provider、gateway。通过getway访问eureka-provider:http://localhost:8080/EUREKA-PROVIDER/hello
几个过滤器的使用
1. AddRequestParameter GatewayFilter
AddRequestParameter GatewayFilter 可以在请求中添加指定参数。
- application.yml配置
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
filters:
- AddRequestParameter=name, pikachues
这样就会给匹配的每个请求添加上name=pikachues的参数和值。
- 结合eureka完整application.yml配置
server:
port: 8080
eureka:
client:
service-url:
defaultZone: http://localhost:1111/eureka
spring:
application:
name: gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启自动代理
routes:
- id: add_request_parameter_route
uri: http://localhost:1116
filters:
- AddRequestParameter=name, pikachues
predicates:
- Method=get
logging:
level:
org.springframework.cloud.gateway: debug
这里的 routes 手动指定了服务的转发地址,设置所有的 GET 方法都会自动添加name=pikachues,http://localhost:1116 是 eureka-producer 项目,我们在此项目中添加一个 filter1() 方法,用来接收转发中添加的参数 name。
@GetMapping("/filter1")
public String filter1(String name){
return "hello "+name;
}
修改完成后分别启动gateway、eureka-provider进行测试。访问地址:http://localhost:1116/finter1,页面返回hello null,说明并没有接受到参数name。
通过网关调用访问,访问地址:http://localhost:8080/finter1,页面返回hello pikachues,说明成功接受到参数name,证明网关在转发的过程中已经通过 filter 添加了设置的参数和值。
- 改进
将转发的服务地址(uri: http://localhost:1116)改为服务名
改进如下:
# 语法 uri:lb://服务名
uri: lb://eureka-provider
修改之后重新调用结果还是一样。
过滤器就介绍到这里,如需了解更多过滤器的用法,请参考https://cloud.spring.io/spring-cloud-gateway/2.2.x/reference/html/