概述
本章主要介绍gateway的另一个重点内容:过滤器工厂。gateway里面的过滤器与Servlet里面的过滤器功能差不多,路由过滤器可以用于修改进入Http请求和返回的Http响应。
分类
按照生命周期
- pre 在业务逻辑之前
- post 在业务逻辑之后
按照种类分
GatewayFilter:需要配置某个路由,才能过滤。如果需要使用全局路由,则需要配置DefaultFilters;
通常我们可以利用GatewayFilter的特点,对某个接口做访问次数的统计;也可以对某个接口做限流操作。
GlobalFilter:全局过滤器,不需要配置路由,系统初始化后作用于所有的路由上。
针对GlobalFilter过滤器,由于是作用于全部路由,因此通常可以用来做黑名单校验、全局的token校验、参数校验.
官方提供了众多的GatewayFilter、GlobalFilter,大家可以通过每个版本的文档进行查阅。
自定义网关过滤器
在实际的业务场景中,使用官方提供的过滤器配置可能无法完全满足需求,因此我们很多时候都会自定义网关过滤器。
自定义全局过滤器
在GateWay中自定义全局过滤器,我们需要实现接口GlobalFilter
,重写filter
方法来满足我们的功能需求。同时,由于容器中存在多个实现接口GlobalFilter
的Bean,我们可以通过实现Ordered
接口来设置过滤器在过滤器链的优先级。
- 获取参数示例:
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 针对请求的过滤 拿到请求,从而获取到请求的 header url 参数...等
// HttpServletRequest 是 web 里面的
// ServerHttpRequest 是 webFlux 里面 响应式里面的
ServerHttpRequest request = exchange.getRequest();
String path = request.getPath().toString();
System.out.println(path);
HttpHeaders headers = request.getHeaders();
System.out.println(headers);
String methodName = Objects.requireNonNull(request.getMethod()).name();
System.out.println(methodName);
String ip = request.getHeaders().getHost().getHostString();
System.out.println(ip);
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1;
}
}
请求服务后,控制台打印内容如下:
/doLogin
[Host:"localhost", Connection:"keep-alive", sec-ch-ua:""Not/A)Brand";v="99", "Google Chrome";v="115", "Chromium";v="115"", sec-ch-ua-mobile:"?0", sec-ch-ua-platform:""Windows"", Upgrade-Insecure-Requests:"1", User-Agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36", Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", Sec-Fetch-Site:"none", Sec-Fetch-Mode:"navigate", Sec-Fetch-User:"?1", Sec-Fetch-Dest:"document", Accept-Encoding:"gzip, deflate, br", Accept-Language:"en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7"]
GET
localhost
- 拦截IP示例
首先明确拦截IP的具体几个步骤:
- 拿到IP
- 校验IP是否符合定义的规范
- 拦截/放行
@Component
public class IpCheckFilter implements GlobalFilter, Ordered {
/**
* 定义 ip 黑名单列表
*/
private static final List<String> BLACK_IP_LIST = Collections.singletonList("127.0.0.1");
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取 ip
String ip = exchange.getRequest().getHeaders().getHost().getHostString();
// 判断是否包含在黑名单
if (!BLACK_IP_LIST.contains(ip)) {
// 不包含,放行
chain.filter(exchange);
}
// 被拦截
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().set("content-type", "application/json;charset=utf-8");
HashMap<String, Object> map = new HashMap<>(4);
map.put("code", HttpStatus.UNAUTHORIZED);
map.put("msg", "无权访问");
ObjectMapper objectMapper = new ObjectMapper();
byte[] bytes = new byte[0];
try {
bytes = objectMapper.writeValueAsBytes(map);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
DataBuffer wrap = response.bufferFactory().wrap(bytes);
return response.writeWith(Mono.just(wrap));
}
@Override
public int getOrder() {
return 0;
}
}
重启服务,然后访问,结果如下:
我们定义的ip拦截器生效了。