1、是什么
路由过滤器可用于修改进入HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用
SpringCloud GateWay 内置了多种路由过滤器,他们都由GateWayFilter的工厂类来产生
官网:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gatewayfilter-factories
2、Spring Cloud GateWay的Filter
1、生命周期 Only Two
1、pre
2、post
2、种类 Only Two
1、GateWayFilter(网关过滤器)
2、GlobalFilter(全局过滤器)
3、常用的GateWayFilter
1、两个主要接口介绍
public class MyLogGateWayFilter implements GlobalFilter, Ordered
2、能干嘛
4、自定义过滤器
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("*****************come in MyLogGateWayFilter"+new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname==null){
log.info("*******用户名为null, 非法用户 ,o(╥﹏╥)o");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0; //这个是优先级
}
网关过滤器
Path路径过滤器
Path路径过滤器可以实现URL重写,通过重写URL可以实现隐藏实际路径提高安全性,易于用户记忆和键入,易于被搜索引擎收录等优点,实现方式如下:
1、RewritePathGateWayFilterFactory
ReWritePath网关过滤器工厂采用路径正则表达式参数和替换参数,使用Java正则表达式来灵活地重写请求路径
2、PrefixPathGateWayFilterFactory
PrefixPath网关过滤器工厂为匹配的URI添加指定前缀
请求
发现可以正常请求,那是因为在filter添加了/product
3、StripPrefixGateWayFilterFactory
StripPrefix网关过滤器工厂采用了一个参数StripPrefix,该参数表示在将请求发送到下游之前从请求中剥离的路径个数。
4、SetpathGateWayFilterFactory
SetPath网关过滤器工厂采用路径模板参数,它提供了一种通过允许模板化路径段来操作请求路径的简单方法,使用了SpringFramework中的URI模板,允许多个匹配段
参数过滤器
AddRequestParameter网关过滤器工厂会将指定参数添加至匹配的下游请求中
Status状态过滤器
SetStatus网关过滤器工厂采用单个状态参数,它必须是有效的Spring HttpStatus,它可以是整数404 或枚举NoT_FOUND 的字符串表示
即使请求成功,也可以更改状态
全局过滤器
全局过滤器不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GateWayFilterChain可识别的过滤器,它是请求业务以及路由的URI转换为真实业务服务请求地址的核心过滤器,不需要配置系统初始化时加载,并作用在每个路由上。
自定义过滤器
自定义网关过滤器
自定义网关过滤器需要实现以下两个接口: GateWayFilter,Ordered。
(1)创建过滤器
/**
* 此过滤器功能为计算请求完成时间
*/
public class MyFilter implements GatewayFilter, Ordered {
private static final String ELAPSED_TIME_BEGIN = "elapsedTimeBegin";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
exchange.getAttributes().put(ELAPSED_TIME_BEGIN, System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute(ELAPSED_TIME_BEGIN);
if (startTime != null) {
System.out.println(exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
}
})
);
}
/*
*过滤器存在优先级,order越大,优先级越低
*/
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
(2)注册过滤器
定义好MyFilter以后其需要跟Route绑定使用,不能在application.yml文件中配置使用
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes().route(r ->
r.path("/abc/**")
//去掉前缀1节
.filters(p->p.stripPrefix(1))
//转发路由
.uri("lb://eureka-client")
//注册自定义过滤器
.filters(new MyFilter())
//给定id
.id("user-service")
).build();
}
自定义全局过滤器
会在所有的路由上
自定义过滤器, 假设对请求头的token进行认证。
/**
* @Author: zhihao
* @Date: 2020/3/31 17:38
* @Description: 自定义过滤器
* @Versions 1.0
**/
@Component //交给框架管理
public class MyGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1.获取请求对象
ServerHttpRequest request = exchange.getRequest();
//2.获取请求头Authenticate
List<String> authenticate = request.getHeaders().get("Authenticate");
if (null == authenticate || authenticate.isEmpty()) {
//说明Authenticate为空,返回错误码,阻止通过网关路由
ServerHttpResponse response = exchange.getResponse();
Map<String,String> resultMap = new LinkedHashMap<>();
resultMap.put("code", "401");
resultMap.put("message", "没有token");
String jsonStr = JSONUtil.toJsonStr(resultMap);
//将错误信息输出页面
DataBuffer dataBuffer = response.bufferFactory().wrap(jsonStr.getBytes());
response.setStatusCode(HttpStatus.UNAUTHORIZED); //状态码
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
Mono<Void> mono = response.writeWith(Mono.just(dataBuffer));
return mono;
//return response.setComplete();
}
//......可以通过
String[] strings = authenticate.toArray(new String[authenticate.size()]);
String str = strings[0];
return chain.filter(exchange);
}
@Override
public int getOrder() {
//值越大则优先级越低。
return -1;
}
}