GateWay中的predicates和Filter
GateWay中的predicates和Filter路由route的组成部分什么是predicates路由route的组成部分id:路由的IDuri: 匹配路由的转发地址predicates:配置该路由的断言,通过PredicateDefinition类进行接收配置。order:路由的优先级,数字越小,优先级越高。Filter: 过滤器 过滤掉一些请求, 满足则转发什么是predicates配置该
·
GateWay中的predicates和Filter
路由route的组成部分
id: 路由的ID
uri: 匹配路由的转发地址
predicates: 配置该路由的断言,通过PredicateDefinition类进行接收配置。
order: 路由的优先级,数字越小,优先级越高。
Filter: 过滤器 过滤掉一些请求, 满足则转发
什么是predicates
配置该路由的断言,通过PredicateDefinition类进行接收配置。
Predicate 来源于Java8,接受输入参数,返回一个布尔值结果
Spring Cloud Gateway 中 Spring 利用 Predicate 的特性实现了各种路由匹配规则
转发的判断条件.
SpringCloud Gateway支持多种方式,常见如:Path、Query、Method、Header等
支持多个Predicate请求的转发是必须满足所有的Predicate后才可以进行路由转发
参数编写规则 XXXRoutePredicateFactory,使用XXX作为参数配置, 例如下面
predicates:
- Host=
- Path=
- Method=
- Header=
- Query=
- Cookie=
源码剖析
我们来看一个类 叫做 BeforeRoutePredicateFactory 类 这个类定义断言行为是 如果当前时间大于我们配置的时候,则不允许转发。源码如下
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* 1: 继承 AbstractRoutePredicateFactory 类
* 2: 重写 apply 方法 定义我们的转发规则
*/
package org.springframework.cloud.gateway.handler.predicate;
import java.time.ZonedDateTime;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import org.springframework.web.server.ServerWebExchange;
/**
* @author Spencer Gibb
*/
public class BeforeRoutePredicateFactory
extends AbstractRoutePredicateFactory<BeforeRoutePredicateFactory.Config> {
/**
* DateTime key.
*/
public static final String DATETIME_KEY = "datetime";
public BeforeRoutePredicateFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList(DATETIME_KEY);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
final ZonedDateTime now = ZonedDateTime.now();
return now.isBefore(config.getDatetime());
}
@Override
public String toString() {
return String.format("Before: %s", config.getDatetime());
}
};
}
public static class Config {
private ZonedDateTime datetime;
public ZonedDateTime getDatetime() {
return datetime;
}
public void setDatetime(ZonedDateTime datetime) {
this.datetime = datetime;
}
}
}
则我们可以同相同的方式 自定义我们自己的转发规则。
怎么做
需求: 自定义我们的规格 配置传入参数必须要有orderId 并且orderId的值配置为10 否则禁止转发 代码如下
package com.leave.cloud.forward;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
/**
* @Description
* @Author 自定义断言工厂
* @Version V1.0.0
* @Date 2021/6/16 0016
*/
@Component
public class ParameterRoutePredicateFactory extends AbstractRoutePredicateFactory<ParameterRoutePredicateFactory.Config> {
//与内部类属性名保持一致
private final static String parameter = "orderId";
public ParameterRoutePredicateFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
//赋值 为 内部类 Config 中的 orderId属性赋值
return Arrays.asList(parameter);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
//获取请求参数体
final String firstOrderId =serverWebExchange.getRequest().getQueryParams().getFirst(parameter);
Assert.notNull(firstOrderId);
return config.getOrderId().equals(firstOrderId);
}
@Override
public String toString() {
return String.format("Parameter: %s", config.getOrderId());
}
};
}
public static class Config {
private String orderId;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
}
}
yml的配置如下
gateway:
routes: #数组形式
- id: xdclass-order-service #路由唯一标识
uri: lb://order-service #想要转发到的地址
order: 1 #优先级,数字越小优先级越高
predicates: #断言 配置参数
- Parameter=10
请求测试截图如下
我们把参数换成9
可以看到404 访问路径不存在 没有进行转发
什么是filters
是一种过滤器,能过滤掉一些不满足要求的request请求。如下图
过滤器生命周期
PRE: 这种过滤器在请求被路由之前调用,一般用于鉴权、限流等
POST:这种过滤器在路由到微服务以后执行,一般用于修改响应结果,比如增加header信息、打点结果日志
网关过滤器分类
局部过滤器GatewayFilter:应用在某个路由上,每个过滤器工厂都对应一个实现类,并且这些类的名称必须以 GatewayFilterFactory 结尾
全局过滤器:作用全部路由上
内置很多局部过滤器,顶级接口 GatewayFilterFactory
内置很多全局过滤器,顶级接口 GlobalFilter
怎么做
需求1: 自定义局部过滤器, 要求订单服务的请求头中必须含有token , 代码如下
package com.leave.cloud.filters;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;
import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
/**
* @Description
* @Author 局部过滤器
* @Version V1.0.0
* @Date 2021/6/16 0016
*/
@Component
public class TokenGatewayFilterFactory extends AbstractGatewayFilterFactory<TokenGatewayFilterFactory.Config> {
/**
* Token_KEY
*/
public static final String Token_KEY = "token";
public static final String enable = "true";
public TokenGatewayFilterFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(Token_KEY);
}
@Override
public GatewayFilter apply(Config config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
//是否开启token验证
if(config.getToken().equals(enable)){
String token = exchange.getRequest().getHeaders().getFirst(Token_KEY);
if (StringUtils.isEmpty(token)) {
return exchange.getResponse().setComplete();
}
}
//生产环境需要验证token的有效性
return chain.filter(exchange);
}
@Override
public String toString() {
return filterToStringCreator(TokenGatewayFilterFactory.this)
.append("token", config.getToken()).toString();
}
};
}
public static class Config {
private String token;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
}
yml配置
gateway:
routes: #数组形式
- id: xdclass-order-service #路由唯一标识
uri: lb://xdclass-order-service #想要转发到的地址
order: 1 #优先级,数字越小优先级越高
predicates: #断言 配置哪个路径才转发
- Path=/order/**
- Parameter=10
filters: #过滤器,请求在传递过程中通过过滤器修改
- StripPrefix=1 #去掉第一层前缀
- Token=true #是否开启token验证
测试调用
不带token
带token
需求2: 自定义全局过滤器, 要求必须携带token,并且token的值为userAuth , 代码如下
package com.leave.cloud.filters;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Objects;
/**
* @Description
* @Author 全局过滤器
* @Version V1.0.0
* @Date 2021/6/16 0016
*/
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private final static String User_Auth = "userAuth";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("token");
if (Objects.isNull(token)) {
return notCheckReturn(exchange);
} else {
if (token.equals(User_Auth)) {
return chain.filter(exchange);
}
return notCheckReturn(exchange);
}
}
private Mono<Void> notCheckReturn(ServerWebExchange exchange) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
/**
* 执行等级
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
测试调用
token值不为userAuth 时
为userAuth时
总结
gateway最大的能力是在于转发,一些过滤最好下沉到各个服务。否则会影响性能
人有逆天之时,天无绝人之路
更多推荐
所有评论(0)
您需要登录才能发言
加载更多