前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Gateway 自定义过滤器

Gateway 自定义过滤器

作者头像
BUG弄潮儿
发布2020-12-17 11:25:47
发布2020-12-17 11:25:47
2.2K00
代码可运行
举报
文章被收录于专栏:JAVA乐园JAVA乐园
运行总次数:0
代码可运行

Spring Cloud Gateway虽然自带有许多实用的GatewayFilter Factory、Gateway Filter、Global Filter,但是在很多业务情景下仍然需要自定义过滤器。实现一些自定义操作,满足业务需求。所以自定义过滤器就显得非常有必要。本文分表介绍自定义Gateway Filter、自定义Global Filter、自定义Gateway Filter Factory。

实现自定义过滤器,其实可以去查看Spring Cloud Gateway自带过滤器源码是如何实现的。

  • 自定义Gateway Filter

实现自定义的Gateway Filter,需要GatewayFilter、Ordered两个接口

代码语言:javascript
代码运行次数:0
复制
/**
 * 此过滤器功能为计算请求完成时间
 */
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;
    }
}



定义好MyFilter以后,其需要跟Route绑定使用,不能在application.yml文件中配置使用

代码语言:javascript
代码运行次数:0
复制
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
     return builder.routes().route(r ->
             r.path("/aa")
                     //转发路由
                     .uri("http://localhost:8080/provider/test")
                     //注册自定义过滤器
                     .filters(new MyFilter())
                    //给定id
                    .id("user-service"))
                    .build();
}

测试结果:可以在控制台看到请求响应时间。

  • 自定义Gateway Filter Factory

很多时候更希望在配置文件中配置Gateway Filter,所以可以自定义过滤器工厂实现。

自定义过滤器工厂需要继承AbstractGatewayFilterFactory

代码语言:javascript
代码运行次数:0
复制
@Component
public class AuthorizeGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthorizeGatewayFilterFactory.Config> {

    private static final Log logger = LogFactory.getLog(AuthorizeGatewayFilterFactory.class);

    private static final String AUTHORIZE_TOKEN = "token";
    private static final String AUTHORIZE_UID = "uid";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public AuthorizeGatewayFilterFactory() {
        super(Config.class);
        logger.info("Loaded GatewayFilterFactory [Authorize]");
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("enabled");
    }

    @Override
    public GatewayFilter apply(AuthorizeGatewayFilterFactory.Config config) {
        return (exchange, chain) -> {
            if (!config.isEnabled()) {
                return chain.filter(exchange);
            }

            ServerHttpRequest request = exchange.getRequest();
            HttpHeaders headers = request.getHeaders();
            String token = headers.getFirst(AUTHORIZE_TOKEN);
            String uid = headers.getFirst(AUTHORIZE_UID);
            if (token == null) {
                token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
            }
            if (uid == null) {
                uid = request.getQueryParams().getFirst(AUTHORIZE_UID);
            }

            ServerHttpResponse response = exchange.getResponse();
            if (StringUtils.isEmpty(token) || StringUtils.isEmpty(uid)) {
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }
            String authToken = stringRedisTemplate.opsForValue().get(uid);
            if (authToken == null || !authToken.equals(token)) {
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }
            return chain.filter(exchange);
        };
    }

    public static class Config {
        // 控制是否开启认证
        private boolean enabled;

        public Config() { }

        public boolean isEnabled() {
            return enabled;
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
    }
}

在application.yml配置使用

代码语言:javascript
代码运行次数:0
复制
# 网关路由配置
spring:
  cloud:
    gateway:
      routes:
      - id: user-center-service
        uri: http://localhost:8080/api/user/list
        predicates:
        - Path=/user/list
        filters:
        # 关键在下面一句,值为true则开启认证,false则不开启
        # 这种配置方式和spring cloud gateway内置的GatewayFilterFactory一致
        - Authorize=true
  • 自定义Global Filter

实现自定义全局过滤器需要继承GlobalFilter和Ordered

代码语言:javascript
代码运行次数:0
复制
@Component
public class MyGloablFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("MyGloablFilter>>>");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

使用它只需要加上@Component注解。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 BUG弄潮儿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档