NACOS学习:04GATEWAY过滤器
springcloud的gateway可以自定义各种过滤器,其中有路由过滤器和全局过滤器
路由过滤器
路由过滤器,可以为每个route配置不同过滤器,也可以配置再default中。
我们自定义一个授权过滤器AuthorizeGatewayFilterFactory(名字固定格式,name+GatewayFilterFactory,配置文件就可以直接使用name作为过滤器名字),集成抽象类AbstractGatewayFilterFactory即可
配置
spring: cloud: gateway: routes: - id: NACOS-CONSUMER uri: lb://spring-cloud-consumer predicates: - Path=/spring-cloud-consumer/** filters: - Authorize=true default-filters: - Authorize=true
代码
@Component @Slf4j public class AuthorizeGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthorizeGatewayFilterFactory.Config> { private static final String AUTHORIZE_TOKEN = "token"; //构造函数,加载Config public AuthorizeGatewayFilterFactory() { //固定写法 super(AuthorizeGatewayFilterFactory.Config.class); log.info("Loaded GatewayFilterFactory [Authorize]"); } //读取配置文件中的参数 赋值到 配置类中 @Override public GatewayFilter apply(Config config) { return (exchange,chain)->{ //判断是否开启授权验证 if (!config.isEnabled()) { return chain.filter(exchange); } ServerHttpRequest request = exchange.getRequest(); HttpHeaders headers = request.getHeaders(); //从请求头中获取token String token = headers.getFirst(AUTHORIZE_TOKEN); if (token == null) { //从请求头参数中获取token token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN); } ServerHttpResponse response = exchange.getResponse(); //如果token为空,直接返回401,未授权 if (StringUtils.isEmpty(token)) { response.setStatusCode(HttpStatus.UNAUTHORIZED); //处理完成,直接拦截,不再进行下去 log.error("AuthorizeGatewayFilterFactory拦截start,token为空,直接拦截,不再进行下去"); return response.setComplete(); }else{ log.info("AuthorizeGatewayFilterFactory拦截start,token={},不拦截,直接放行",token); } /** * todo chain.filter(exchange) 之前的都是过滤器的前置处理 * * chain.filter().then( * 过滤器的后置处理........... * ) */ //授权正常,继续下一个过滤器链的调用 return chain.filter(exchange) .then(Mono.fromRunnable(()->{ HttpStatus statusCode = response.getStatusCode(); String path = request.getPath().pathWithinApplication().value(); InetSocketAddress remoteAddress = request.getRemoteAddress(); log.info("AuthorizeGatewayFilterFactory后置处理,请求路径:{},远程IP地址:{},响应码:{}", path, remoteAddress, statusCode); })); }; } @Override public List<String> shortcutFieldOrder() { //Config.enabled return Arrays.asList("enabled"); } @Data @AllArgsConstructor @NoArgsConstructor public static class Config { // 控制是否开启认证 private boolean enabled; } }
全局过滤器
全局过滤器默认全局生效,无需配置,只要实现接口GlobalFilter 并且注册成bean。
代码
@Slf4j @Component @Order(value = Integer.MIN_VALUE) public class MyGlobalFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); String path = request.getPath().pathWithinApplication().value(); InetSocketAddress remoteAddress = request.getRemoteAddress(); log.info("MyGlobalFilter拦截前置处理"); return chain //继续调用filter .filter(exchange) //filter的后置处理 .then(Mono.fromRunnable(()->{ ServerHttpResponse response = exchange.getResponse(); HttpStatus statusCode = response.getStatusCode(); log.info("MyGlobalFilter拦截后置处理,请求路径:{},远程IP地址:{},响应码:{}", path, remoteAddress, statusCode); })); } }
过滤器执行顺序
日志打印如下
2022-09-28 16:01:03.636 INFO 55000 --- [ctor-http-nio-2] c.s.g.f.AuthorizeGatewayFilterFactory : AuthorizeGatewayFilterFactory拦截start,token=2,不拦截,直接放行 2022-09-28 16:01:03.704 INFO 55000 --- [oundedElastic-4] com.sephy.gateway.filter.MyGlobalFilter : MyGlobalFilter拦截前置处理 2022-09-28 16:01:04.244 INFO 55000 --- [ctor-http-nio-5] com.sephy.gateway.filter.MyGlobalFilter : MyGlobalFilter拦截后置处理,请求路径:/hello/name,远程IP地址:/0:0:0:0:0:0:0:1:52392,响应码:200 OK 2022-09-28 16:01:04.244 INFO 55000 --- [ctor-http-nio-5] c.s.g.f.AuthorizeGatewayFilterFactory : AuthorizeGatewayFilterFactory后置处理,请求路径:/hello/name,远程IP地址:/0:0:0:0:0:0:0:1:52392,响应码:200 OK
可知,路由过滤器先执行,再到全局过滤器,然后返回时则相反。如图
很不错的文章