[TOC]
# 1. gateway基本概念
* Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。
* Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代ZUUL,其不仅提供统一的**路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。**
* 内置了 10 种 Router,使得我们可以直接配置一下就可以随心所欲的根据 Header、或者 Path、或者 Host、或者 Query 来做路由。
* **过滤器分为Filter(内置20种) 和全局 Filter两种(内置9种)**
![](https://img.kancloud.cn/a9/48/a94860bf14437fb5331a84e5742b63a2_1502x494.png)
![](https://img.kancloud.cn/ac/e4/ace44633c2e8d75e73b403dffe2200ff_1794x1006.png)
![](https://img.kancloud.cn/66/85/6685de69532dfd4477b3b1dabeaccb8c_1862x716.png)
# 2. gateway 请求路由
就是使用Predicate实现一组匹配规则,方便让请求过来找到对应的 Route 进行处理,接下来我们接下 Spring Cloud GateWay 内置几种 Predicate 的使用。
## 2.1 通过时间匹配
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]
~~~
这样设置就意味着在这个时间段内可以匹配到此路由,超过这个时间段范围则不会进行匹配。通过时间匹配路由的功能很酷,可以用在限时抢购的一些场景中。
## 2.2 通过 Cookie 匹配
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 错误。
## 2.3 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 证明没有匹配。
## 2.4 通过 Host 匹配
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 错误。
## 2.5 通过请求方式匹配
可以通过是 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 没有找到,证明没有匹配上路由
## 2.6 通过请求路径匹配
Path Route Predicate 接收一个匹配路径的参数来判断是否走路由。
~~~
spring:
cloud:
gateway:
routes:
- id: host_route
uri: http://ityouknow.com
predicates:
- Path=/foo/{segment}
~~~
如果请求路径符合要求,则此路由将匹配,例如:/foo/1 或者 /foo/bar。
`- Path=/foo/** ` 配置所有/foot开头的请求
使用 curl 测试,命令行输入:
~~~
curl http://localhost:8080/foo/1
curl http://localhost:8080/foo/xx
curl http://localhost:8080/boo/xx
~~~
经过测试第一和第二条命令可以正常获取到页面返回值,最后一个命令报 404,证明路由是通过指定路由来匹配。
## 2.7 通过请求参数匹配
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, 证明路由需要匹配正则表达式才会进行路由。
## 2.8 通过请求 ip 地址进行匹配
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 地址进行测试。
果请求的远程地址是 192.168.1.10,则此路由将匹配。
## 2.9 组合使用
上面为了演示各个 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]
~~~
## 方式二:编码
以上是基于配置文件方式,还可以编码的方式添加路由
配置访问路由端口`/guonei`链接到`http://news.baidu.com/guonei`的示例代码
~~~
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GatewayConfigration {
@Bean
public RouteLocator myRouteLocator(RouteLocatorBuilder builder){
RouteLocatorBuilder.Builder routes=builder.routes();
routes.route("my_path_routh",r->r.path("/guonei").uri("http://news.baidu.com/guonei"));
return routes.build();
}
}
~~~
# 3. gateway请求过滤 filter
* predicate断言是对请求路由处理,找到对应的后台服务,而在路由处理之前,需要经过`pre`类型的filter,处理放回响应后由`post`类型的请求处理,和mvc的过滤器类似。
* 在`pre`类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等
* 在`post`类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等。
## 3.1 生命周期
Spring Cloud Gateway同zuul类似,有“pre”和“post”两种方式的filter。客户端的请求先经过“pre”类型的filter,然后将请求转发到具体的业务服务,比如上图中的user-service,收到业务服务的响应之后,再经过“post”类型的filter处理,最后返回响应到客户端。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190601011115924.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9mb3JlenAuYmxvZy5jc2RuLm5ldA==,size_16,color_FFFFFF,t_70)
与zuul不同的是,filter除了分为“pre”和“post”两种方式的filter外,在Spring Cloud Gateway中,filter从作用范围可分为另外两种,一种是针对于单个路由的gateway filter,它在配置文件中的写法同predict类似;另外一种是针对于所有路由的global gateway filer。现在从作用范围划分的维度来讲解这两种filter。
## 3.2 AddRequestHeader GatewayFilter Factory
**增加请求头过滤器**
创建工程,引入相关的依赖,包括spring boot 版本2.0.5,spring Cloud版本Finchley,gateway依赖如下:
~~~
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
~~~
在工程的配置文件中,加入以下的配置:
~~~text
server:
port: 8081
spring:
profiles:
active: add_request_header_route
---
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: http://httpbin.org:80/get
filters:
- AddRequestHeader=X-Request-Foo, Bar
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
profiles: add_request_header_route
~~~
在上述的配置中,工程的启动端口为8081,配置文件为add\_request\_header\_route,在add\_request\_header\_route配置中,配置了roter的id为add\_request\_header\_route,路由地址为http://httpbin.org:80/get,该router有AfterPredictFactory,有一个filter为AddRequestHeaderGatewayFilterFactory(约定写成AddRequestHeader),AddRequestHeader过滤器工厂会在请求头加上一对请求头,名称为X-Request-Foo,值为Bar。为了验证AddRequestHeaderGatewayFilterFactory是怎么样工作的,查看它的源码,AddRequestHeaderGatewayFilterFactory的源码如下:
~~~
public class AddRequestHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest().mutate()
.header(config.getName(), config.getValue())
.build();
return chain.filter(exchange.mutate().request(request).build());
};
}
}
~~~
由上面的代码可知,根据旧的ServerHttpRequest创建新的 ServerHttpRequest ,在新的ServerHttpRequest加了一个请求头,然后创建新的 ServerWebExchange ,提交过滤器链继续过滤。
启动工程,通过curl命令来模拟请求:
~~~
curl localhost:8081
~~~
最终显示了从 http://httpbin.org:80/get得到了请求,响应如下:
~~~
{
"args": {},
"headers": {
"Accept": "*/*",
"Connection": "close",
"Forwarded": "proto=http;host=\"localhost:8081\";for=\"0:0:0:0:0:0:0:1:56248\"",
"Host": "httpbin.org",
"User-Agent": "curl/7.58.0",
"X-Forwarded-Host": "localhost:8081",
"X-Request-Foo": "Bar"
},
"origin": "0:0:0:0:0:0:0:1, 210.22.21.66",
"url": "http://localhost:8081/get"
}
~~~
可以上面的响应可知,确实在请求头中加入了X-Request-Foo这样的一个请求头,在配置文件中配置的AddRequestHeader过滤器工厂生效。
跟AddRequestHeader过滤器工厂类似的还有AddResponseHeader过滤器工厂,在此就不再重复。
## 3.3 RewritePath GatewayFilter Factory
**路径重写**
在Nginx服务启中有一个非常强大的功能就是重写路径,Spring Cloud Gateway默认也提供了这样的功能,这个功能是Zuul没有的。在配置文件中加上以下的配置:
~~~
spring:
profiles:
active: rewritepath_route
---
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: https://blog.csdn.net
predicates:
- Path=/foo/**
filters:
- RewritePath=/foo/(?<segment>.*), /$\{segment}
profiles: rewritepath_route
~~~
上面的配置中,所有的/foo/\*\*开始的路径都会命中配置的router,并执行过滤器的逻辑,在本案例中配置了RewritePath过滤器工厂,此工厂将/foo/(?.\*)重写为{segment},然后转发到https://blog.csdn.net。比如在网页上请求localhost:8081/foo/forezp,此时会将请求转发到https://blog.csdn.net/forezp的页面,比如在网页上请求localhost:8081/foo/forezp/1,页面显示404,就是因为不存在https://blog.csdn.net/forezp/1这个页面。
## 3.4 自定义过滤器
Spring Cloud Gateway内置了19种强大的过滤器工厂,能够满足很多场景的需求,那么能不能自定义自己的过滤器呢,当然是可以的。在spring Cloud Gateway中,过滤器需要实现GatewayFilter和Ordered2个接口。写一个RequestTimeFilter,代码如下:
统计请求耗时:
### 3.4.1 定义filter
~~~
public class RequestTimeFilter implements GatewayFilter, Ordered {
private static final Log log = LogFactory.getLog(GatewayFilter.class);
private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
if (startTime != null) {
log.info(exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
}
})
);
}
@Override
public int getOrder() {
return 0;
}
}
~~~
在上面的代码中,Ordered中的int getOrder()方法是来给过滤器设定优先级别的,值越大则优先级越低。还有有一个filterI(exchange,chain)方法,在该方法中,先记录了请求的开始时间,并保存在ServerWebExchange中,此处是一个“pre”类型的过滤器,然后再chain.filter的内部类中的run()方法中相当于"post"过滤器,在此处打印了请求所消耗的时间。
### 3.4.2 注册filter
然后将该过滤器注册到router中,代码如下:
~~~
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("/customer/**")
.filters(f -> f.filter(new RequestTimeFilter())
.addResponseHeader("X-Response-Default-Foo", "Default-Bar"))
.uri("http://httpbin.org:80/get")
.order(0)
.id("customer_filter_router")
)
.build();
}
~~~
重启程序,通过curl命令模拟请求:
~~~
curl localhost:8081/customer/123
~~~
在程序的控制台输出一下的请求信息的日志:
~~~
2018-11-16 15:02:20.177 INFO 20488 --- [ctor-http-nio-3] o.s.cloud.gateway.filter.GatewayFilter : /customer/123: 152ms
~~~
## 3.5 自定义过滤器工厂
在上面的自定义过滤器中,有没有办法自定义过滤器工厂类呢?这样就可以在配置文件中配置过滤器了。现在需要实现一个过滤器工厂,在打印时间的时候,可以设置参数来决定是否打印请参数。查看GatewayFilterFactory的源码,可以发现GatewayFilterfactory的层级如下:
![微信截图_20181204175448.png](https://imgconvert.csdnimg.cn/aHR0cHM6Ly93d3cuZmFuZ3poaXBlbmcuY29tL2ltZy9qaWFuc2h1LzIyNzk1OTQtZjk3ZTEwNDVjZWJjOTU0Yy5wbmc?x-oss-process=image/format,png)
过滤器工厂的顶级接口是GatewayFilterFactory,我们可以直接继承它的两个抽象类来简化开发AbstractGatewayFilterFactory和AbstractNameValueGatewayFilterFactory,这两个抽象类的区别就是前者接收一个参数(像StripPrefix和我们创建的这种),后者接收两个参数(像AddResponseHeader)。
过滤器工厂的顶级接口是GatewayFilterFactory,有2个两个较接近具体实现的抽象类,分别为AbstractGatewayFilterFactory和AbstractNameValueGatewayFilterFactory,这2个类前者接收一个参数,比如它的实现类RedirectToGatewayFilterFactory;后者接收2个参数,比如它的实现类AddRequestHeaderGatewayFilterFactory类。现在需要将请求的日志打印出来,需要使用一个参数,这时可以参照RedirectToGatewayFilterFactory的写法。
~~~
public class RequestTimeGatewayFilterFactory extends AbstractGatewayFilterFactory<RequestTimeGatewayFilterFactory.Config> {
private static final Log log = LogFactory.getLog(GatewayFilter.class);
private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";
private static final String KEY = "withParams";
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(KEY);
}
public RequestTimeGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
if (startTime != null) {
StringBuilder sb = new StringBuilder(exchange.getRequest().getURI().getRawPath())
.append(": ")
.append(System.currentTimeMillis() - startTime)
.append("ms");
if (config.isWithParams()) {
sb.append(" params:").append(exchange.getRequest().getQueryParams());
}
log.info(sb.toString());
}
})
);
};
}
public static class Config {
private boolean withParams;
public boolean isWithParams() {
return withParams;
}
public void setWithParams(boolean withParams) {
this.withParams = withParams;
}
}
}
~~~
在上面的代码中 apply(Config config)方法内创建了一个GatewayFilter的匿名类,具体的实现逻辑跟之前一样,只不过加了是否打印请求参数的逻辑,而这个逻辑的开关是config.isWithParams()。静态内部类类Config就是为了接收那个boolean类型的参数服务的,里边的变量名可以随意写,但是要重写List shortcutFieldOrder()这个方法。
。
需要注意的是,在类的构造器中一定要调用下父类的构造器把Config类型传过去,否则会报ClassCastException
最后,需要在工程的启动文件Application类中,向Srping Ioc容器注册RequestTimeGatewayFilterFactory类的Bean。
~~~
@Bean
public RequestTimeGatewayFilterFactory elapsedGatewayFilterFactory() {
return new RequestTimeGatewayFilterFactory();
}
~~~
然后可以在配置文件中配置如下:
~~~
spring:
profiles:
active: elapse_route
---
spring:
cloud:
gateway:
routes:
- id: elapse_route
uri: http://httpbin.org:80/get
filters:
- RequestTime=false
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
profiles: elapse_route
~~~
启动工程,在浏览器上访问localhost:8081?name=forezp,可以在控制台上看到,日志输出了请求消耗的时间和请求参数。
## 3.6 global filter
Spring Cloud Gateway根据作用范围划分为GatewayFilter和GlobalFilter,二者区别如下:
* GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上
* GlobalFilter : **全局过滤器,不需要在配置文件中配置,作用在所有的路由上**,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器,它为请求业务以及路由的URI转换为真实业务服务的请求地址的核心过滤器,不需要配置,系统初始化时加载,并作用在每个路由上。
Spring Cloud Gateway框架内置的GlobalFilter如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190601011412503.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9mb3JlenAuYmxvZy5jc2RuLm5ldA==,size_16,color_FFFFFF,t_70)
上图中每一个GlobalFilter都作用在每一个router上,能够满足大多数的需求。但是如果遇到业务上的定制,可能需要编写满足自己需求的GlobalFilter。在下面的案例中将讲述如何编写自己GlobalFilter,该GlobalFilter会校验请求中是否包含了请求参数“token”,如何不包含请求参数“token”则不转发路由,否则执行正常的逻辑。代码如下:
~~~
public class TokenFilter implements GlobalFilter, Ordered {
Logger logger=LoggerFactory.getLogger( TokenFilter.class );
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getQueryParams().getFirst("token");
if (token == null || token.isEmpty()) {
logger.info( "token is empty..." );
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -100;
}
}
~~~
在上面的TokenFilter需要实现GlobalFilter和Ordered接口,这和实现GatewayFilter很类似。然后根据ServerWebExchange获取ServerHttpRequest,然后根据ServerHttpRequest中是否含有参数token,如果没有则完成请求,终止转发,否则执行正常的逻辑。
然后需要将TokenFilter在工程的启动类中注入到Spring Ioc容器中,代码如下:
~~~java
@Bean
public TokenFilter tokenFilter(){
return new TokenFilter();
}
~~~
启动工程,使用curl命令请求:
~~~
curl localhost:8081/customer/123
~~~
可以看到请没有被转发,请求被终止,并在控制台打印了如下日志:
~~~
2018-11-16 15:30:13.543 INFO 19372 --- [ctor-http-nio-2] gateway.TokenFilter : token is empty...
~~~
上面的日志显示了请求进入了没有传“token”的逻辑。
## 总结
本篇文章讲述了Spring Cloud Gateway中的过滤器,包括GatewayFilter和GlobalFilter。从官方文档的内置过滤器讲起,然后讲解自定义GatewayFilter、GatewayFilterFactory以及自定义的GlobalFilter。有很多内置的过滤器并没有讲述到,比如限流过滤器,这个我觉得是比较重要和大家关注的过滤器,将在之后的文章讲述。
- springcloud
- springcloud的作用
- springboot服务提供者和消费者
- Eureka
- ribbon
- Feign
- feign在微服务中的使用
- feign充当http请求工具
- Hystrix 熔断器
- Zuul 路由网关
- Spring Cloud Config 分布式配置中心
- config介绍与配置
- Spring Cloud Config 配置实战
- Spring Cloud Bus
- gateway
- 概念讲解
- 实例
- GateWay
- 统一日志追踪
- 分布式锁
- 1.redis
- springcloud Alibaba
- 1. Nacos
- 1.1 安装
- 1.2 特性
- 1.3 实例
- 1. 整合nacos服务发现
- 2. 整合nacos配置功能
- 1.4 生产部署方案
- 环境隔离
- 原理讲解
- 1. 服务发现
- 2. sentinel
- 3. Seata事务
- CAP理论
- 3.1 安装
- 分布式协议
- 4.熔断和降级
- springcloud与alibba
- oauth
- 1. abstract
- 2. oauth2 in micro-service
- 微服务框架付费
- SkyWalking
- 介绍与相关资料
- APM系统简单对比(zipkin,pinpoint和skywalking)
- server安装部署
- agent安装
- 日志清理
- 统一日志中心
- docker安装部署
- 安装部署
- elasticsearch 7.x
- logstash 7.x
- kibana 7.x
- ES索引管理
- 定时清理数据
- index Lifecycle Management
- 没数据排查思路
- ELK自身组件监控
- 多租户方案
- 慢查询sql
- 日志审计
- 开发
- 登录认证
- 链路追踪
- elk
- Filebeat
- Filebeat基础
- Filebeat安装部署
- 多行消息Multiline
- how Filebeat works
- Logstash
- 安装
- rpm安装
- docker安装Logstash
- grok调试
- Grok语法调试
- Grok常用表达式
- 配置中常见判断
- filter提取器
- elasticsearch
- 安装
- rpm安装
- docker安装es
- 使用
- 概念
- 基础
- 中文分词
- 统计
- 排序
- 倒排与正排索引
- 自定义dynamic
- 练习
- nested object
- 父子关系模型
- 高亮
- 搜索提示
- kibana
- 安装
- docker安装
- rpm安装
- 整合
- 收集日志
- 慢sql
- 日志审计s
- 云
- 分布式架构
- 分布式锁
- Redis实现
- redisson
- 熔断和降级