gateway是springcloud推出的第二代网关,取代了之前的zuul。
第一个简单的gateway
创建一个springboot项目,引入gateway的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
首先需要在改springbot项目中注入一个RouteLocator类型的bean
@SpringBootApplication
@RestController
public class Gatewayservice7106Application {
public static void main(String[] args) {
SpringApplication.run(Gatewayservice7106Application.class, args);
}
@Bean
public RouteLocator myRoute(RouteLocatorBuilder builder) {
return builder.routes().route(p ->
p.path("/get")
.filters(f -> f.setRequestHeader("token", "qwer"))
.uri("http://httpbin.org:80")
).route(p ->
p.path("/posts")
.filters(f -> f.hystrix(config
-> config.setName("cmd").setFallbackUri("forward:/fallback")))
.uri("http://httpbin.org:80")).build();
}
@GetMapping("/fallback")
public String fallBack() {
return "dead";
}
}
这里通过RouteLocatorBuilder来创建路由。由route()方法来路由请求,该方法返回一个RouteLocatorBuilder类里面的Router类,可链式写。
该route方法里面依次定义了匹配的请求路径,需要执行的过滤器,最后需要转发的地址。第二个过滤器中使用了Hystrix。
predicate
springcloud里面的predicate用于请求和路由进行匹配。
datetime:时间校验
AfterRoutePredicateFactory:请求时间满足在配置时间之后
BeforeRoutePredictateFactory:请求时间满足在配置时间之前
BetweenRoutePredicateFactory:请求时间满足配置时间时间
Cookie:cookie校验
CookieRoutePredicateFactory:指定Cookie正则匹配
Header:请求头校验
HeaderRoutePredicateFactory:请求指定Header正则匹配指定的值
CloudFoundryRouteServiceRoutePredicateFactory:请求Header是否包含指定名称
Host校验:
HostRoutePredicateFactory:请求Host匹配指定的值
Method校验:
MethodRoutePredicateFactory:请求的method匹配配置的方法名
Path校验:
PathRoutePredicateFactory:请求路径正则匹配
Queryparam校验:
QueryRoutePredicateFactory:请求参数正则匹配指定的值
RemoteAddr 请求远程地址校验:
RemoteAddrRoutePredicateFactory:请求远程地址匹配指定的值
每一种predicate都会对当前的客户端请求进行判断,是否满足当前的要求,如果满足则交给当前请求处理。如果有很多个Predicate,并且一个请求满足多个Predicate,则按照配置的顺序第一个生效。
下面操作一下这些predicate,还是用上面的gateway工程:
在application.yml文件中配置如下
server:
port: 7106
spring:
profiles:
active: after_route
---
spring:
cloud:
gateway:
routes:
- id: after_route
uri: http://httpbin.org:80/get
predicates:
- After=2019-01-20T10:15:47.789+08:00
prefiles: after_route
AfterRoutePredicateFactory
其中,spring.profiles.active:after_route表示启动文件还有一个,名为after_route。“—”表示新建一个yml文件,用profiles指定这个文件名。routes:之后的就是路由配置,id必须要有的,每个route都需要一个唯一的id,uri指路由转发的地址,predicates是配置上面的那些predicate类型。-after指定的就是AfterRoutePredicateFactory,其时间格式为:年-月-日T时-分-秒.毫秒+时区。
这里配置的时间为1月20号,请求应该是会转发到http://httpbin.org:80/get去的。
访问一下,发现确实转发到该地址了
如果把时间配置在当前时间之后,再次请求就会404。
BeforeRoutePredictateFactory
和AfterRoutePredicateFactory相反。
把上面的application.yml文件中配置修改一下,使用BeforeRoutePredictateFactory
predicates:
# - After=2019-01-20T10:15:47.789+08:00
- Before=2019-08-20T10:15:47.789+08:00
请求一下http://localhost:7106/,就会转发到http://httpbin.org:80/get。
如果把时间改为1月份,再次访问就404了
如下
BetweenRoutePredicateFactory
这个就是配置一个时间段了。和上面两个功能一样
把predicates配置修改为如下
predicates:
- Between=2019-01-20T10:15:47.789+08:00,2019-02-20T10:15:47.789+08:00
请求就404了。
CookieRoutePredicateFactory
这个就是校验请求中是否含有设置的cookie。
把配置文件中predicates的设置为如下,请求一下,就转发到http://httpbin.org:80/getl了
predicates:
- Cookie=name,zgq
请求的cookie值随便改一个,就404了
HeaderRoutePredicateFactory
匹配请求头中是否包含设置的请求头,并且值是否匹配
把配置文件中predicates的设置为如下,请求头设置一个X-name=12,请求一下,就转发到http://httpbin.org:80/getl了
predicates:
- Header=X-name,\d+ #请求头中是否包含X-name的请求头,并且值为数值
X-name值改为字符串,就404了
CloudFoundryRouteServiceRoutePredicateFactory
匹配请求head是否包含指定值
HostRoutePredicateFactory
匹配请求头中host是否满足条件
把配置文件中predicates的设置为如下,请求头设置一个Host=y.yuchai.com,请求一下,就转发到http://httpbin.org:80/getl了
predicates:
- Host=y.yuchai.com
Host值改与一下,就404了
MethodRoutePredicateFactory
匹配请求类型
把配置文件中predicates的设置为如下,get方式请求一下,就转发到http://httpbin.org:80/getl了
predicates:
- Method=Get
请求方式改为post,就404了
QueryRoutePredicateFactory
匹配请求中的参数
把配置文件中predicates的设置为如下,请求一下,就转发到http://httpbin.org:80/getl了
predicates:
- Query=name,zgq #请求参数中有name=zgq则匹配
参数值或名改一下,就404了
PathRoutePredicateFactory
匹配请求路径是否符合配置的规则
把配置文件中predicates的设置为如下,请求一下,就转发到http://httpbin.org:80/getl了
predicates:
- Path=/getName #请求路径中有/getName则匹配
路径改一下,就404了
gateway的路由过滤
gateway filter按照作用时间分为pre和post类型的过滤器。pre类型的过滤器为gateway转发请求之前起作用,post类型的过滤器为gateway收到业务服务响应之后,返回响应给客户端之前这段时间内起作用。
按照作用范围,又分为全局过滤器和单个路由的过滤器。
gateway提供的默认单个路由的过滤器有19个。
试下AddRequestHeader的过滤器,和Predicate配置一样,在yml中配置即可,如下
spring:
cloud:
gateway:
routes:
- id: after_route
uri: http://httpbin.org:80/get
filters:
- AddRequestHeader=X-name,zgq
predicates:
- After=2019-01-20T10:15:47.789+08:00
这样,在请求到达gateway之后,会加上一个请求头,再转发给http://httpbin.org:80/get。
其他我没找到,等我以后再来补充 =_= !
自定义过滤器
自定义单个路由的过滤器
需要创建类实现GatewayFilter接口和Orders接口
public class MyFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
exchange.getAttributes().put("requestTimeBegin", System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute("requestTimeBegin");
if (startTime !=null) {
System.out.println("请求耗时"+ (System.currentTimeMillis() - startTime));
}
})
);
}
@Override
public int getOrder() {
return 0;
}
}
然后注册该过滤器到route中
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
return builder.routes().route(
r -> r.path("/*")
.filters(f -> f.filter(new MyFilter())
.addRequestHeader("X-name", "zgq123"))
.uri("http://httpbin.org:80/get")
.order(0)
.id("my_filer")
).build();
}
然后访问一下,请求头中加入了一个“x-name”的请求头
自定义过滤器工厂
public class MyFilterFactory extends AbstractGatewayFilterFactory<MyFilterFactory.Config> {
public MyFilterFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("withParam");
}
@Override
public GatewayFilter apply(MyFilterFactory.Config config) {
return (exchange, chain) -> {
exchange.getAttributes().put("startTime", System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute("startTime");
if (startTime != null) {
System.out.println("耗时" + (System.currentTimeMillis() - startTime));
}
})
);
};
}
public static class Config {
private boolean withParam;
public boolean isWithParam() {
return withParam;
}
public void setWithParam(boolean withParam) {
this.withParam = withParam;
}
}
}
注册该Factory到IOC中
@Bean
public MyFilterFactory registryMyFilterFactory() {
return new MyFilterFactory();
}
最后可以在yml文件中配置该过滤器工厂了
spring:
cloud:
gateway:
routes:
- id: after_route
uri: http://httpbin.org:80/get
filters:
- MyFilterFactory=false
predicates:
- After=2019-01-20T10:15:47.789+08:00
自定义全局过滤器
gateway有几个默认的全局过滤器,对每一个路由都起作用,不需要配置,默认启用的
自定义全局过滤器需要实现GlobalFilter,Ordered接口
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getAttribute("token");
if (token == null || token.isEmpty()) {
System.out.println("token is empty");
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -10;
}
}
注册到IOC里面
@Bean
public MyGlobalFilter registryMyGlobelFilter() {
return new MyGlobalFilter();
}