本篇博客主要搬运自开课吧提供的课堂笔记,目的是方便自身复习查找,如有不当之处,请联系博主
过滤器执行次序
Spring-Cloud-Gateway 基于过滤器实现,同 zuul 类似,有pre和post两种方式的 filter,分别处理前置逻辑和后置逻辑。客户端的请求先经过pre类型的 filter,然后将请求转发到具体的业务服务,收到业务服务的响应之后,再经过post类型的 filter 处理,最后返回响应到客户端。
过滤器执行流程如下,order 越大,优先级越低,如图所示。
过滤器分为全局过滤器和局部过滤器。
- 全局过滤器:对所有路由生效
- 局部过滤器:对指定的路由生效
全局过滤器
实现 GlobalFilter 和 Ordered,重写相关方法,加入到spring容器管理即可,无需配置,全局过滤器对所有的路由都有效。代码如下。
@Configuration
public class FilterConfig
{
@Bean
public GlobalFilter a()
{
return new AFilter();
}
@Bean
public GlobalFilter b()
{
return new BFilter();
}
@Bean
public GlobalFilter c()
{
return new CFilter();
}
@Bean
public GlobalFilter myAuthFilter()
{
return new MyAuthFilter();
}
@Slf4j
static class AFilter implements GlobalFilter, Ordered
{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
log.info("AFilter前置逻辑");
return chain.filter(exchange).then(Mono.fromRunnable(() ->
{
log.info("AFilter后置逻辑");
}));
}
// 值越小,优先级越高
@Override
public int getOrder()
{
return HIGHEST_PRECEDENCE + 100;
}
}
@Slf4j
static class BFilter implements GlobalFilter, Ordered
{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
log.info("BFilter前置逻辑");
return chain.filter(exchange).then(Mono.fromRunnable(() ->
{
log.info("BFilter后置逻辑");
}));
}
@Override
public int getOrder()
{
return HIGHEST_PRECEDENCE + 200;
}
}
@Slf4j
static class CFilter implements GlobalFilter, Ordered
{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
log.info("CFilter前置逻辑");
return chain.filter(exchange).then(Mono.fromRunnable(() ->
{
log.info("CFilter后置逻辑");
}));
}
@Override
public int getOrder()
{
return HIGHEST_PRECEDENCE + 300;
}
}
@Slf4j
static class MyAuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("MyAuthFilter权限过滤器");
String token = exchange.getRequest().getHeaders().getFirst("token");
if (StringUtils.isBlank(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE + 400;
}
}
}
配置文件如下:
cloud:
gateway:
routes:
- id: url-proxy-2
uri: lb://cloud-payment-service
predicates:
- Path=/payment/**
定义了4个全局过滤器,顺序为A>B>C>MyAuthFilter,其中全局过滤器MyAuthFilter中判断令牌是否存在,如果令牌不存在,则返回401状态码,表示没有权限访问,使用Postman执行请求,如图所示。
如果码掉过滤器MyAuthFilter,则可以在控制台中看出order大小对过滤器执行顺序的影响。
局部过滤器
定义局部过滤器步骤如下。
- 需要实现GatewayFilter, Ordered,实现相关的方法
- 包装GatewayFilter,产生GatewayFilterFactory
- GatewayFilterFactory加入到过滤器工厂,并且注册到spring容器中。
- 在配置文件中进行配置,如果不配置则不启用此过滤器规则。
接下来定义局部过滤器,对于请求头user-id校验,如果不存在user-id请求头,直接返回状态码406。代码如下。
@Component
public class UserIdCheckGatewayFilterFactory extends AbstractGatewayFilterFactory<Object>
{
@Override
public GatewayFilter apply(Object config)
{
return new UserIdCheckGateWayFilter();
}
@Slf4j
static class UserIdCheckGateWayFilter implements GatewayFilter, Ordered
{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
String url = exchange.getRequest().getPath().pathWithinApplication().value();
log.info("请求URL:" + url);
log.info("method:" + exchange.getRequest().getMethod());
//获取header
String userId = exchange.getRequest().getHeaders().getFirst("user-id");
log.info("userId:" + userId);
if (StringUtils.isBlank(userId))
{
log.info("*****头部验证不通过,请在头部输入 user-id");
//终止请求,直接回应
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
// 值越小,优先级越高
@Override
public int getOrder()
{
return HIGHEST_PRECEDENCE;
}
}
}
配置文件application.yml代码如下。
spring:
cloud:
gateway:
routes:
- id: service14
uri: http://127.0.0.1:9001
predicates:
- Path=/{segment}
default-filters:
- PrefixPath=/payment
- UserIdCheck