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

可知,路由过滤器先执行,再到全局过滤器,然后返回时则相反。如图

image.png


很不错的文章

{context}