首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Spring Cloud Gateway-自定义GatewayFilter

Spring Cloud Gateway-自定义GatewayFilter

作者头像
Throwable
发布于 2020-06-23 08:28:06
发布于 2020-06-23 08:28:06
6.6K0
举报
文章被收录于专栏:Throwable's BlogThrowable's Blog

前提

GatewayFilter的作用域是指定的路由配置,路由配置选项里面需要通过filters指定想要使用的GatewayFilter列表。我们可以通过自定义GatewayFilter,做额外的扩展,实现一些内建GatewayFilter不存在的功能,并且应用到我们的路由配置中。

如何自定义GatewayFilter

需要定制GatewayFilter,则需要实现org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory接口,GatewayFilterFactory的定义如下:

代码语言:javascript
复制
@FunctionalInterface
public interface GatewayFilterFactory<C> extends ShortcutConfigurable, Configurable<C> {

	String NAME_KEY = "name";

	String VALUE_KEY = "value";

	default GatewayFilter apply(Consumer<C> consumer) {
		C config = newConfig();
		consumer.accept(config);
		return apply(config);
	}

	default Class<C> getConfigClass() {
		throw new UnsupportedOperationException("getConfigClass() not implemented");
	}

	@Override
	default C newConfig() {
		throw new UnsupportedOperationException("newConfig() not implemented");
	}

	GatewayFilter apply(C config);

	default String name() {
		return NameUtils.normalizeFilterFactoryName(getClass());
	}

	@Deprecated
	default ServerHttpRequest.Builder mutate(ServerHttpRequest request) {
		return request.mutate();
	}
}  

public interface ShortcutConfigurable {

    default ShortcutType shortcutType() {
        return ShortcutType.DEFAULT;
    }

    default List<String> shortcutFieldOrder() {
        return Collections.emptyList();   
    }

    default String shortcutFieldPrefix() {
        return "";
    }    
}

public interface Configurable<C> {

	Class<C> getConfigClass();

	C newConfig();
}

看起来挺复杂的,但是实际上很多都是接口的默认方法,实际上要实现的方法很少。

另一种方式是继承org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory,看抽象类AbstractGatewayFilterFactory的定义:

代码语言:javascript
复制
public abstract class AbstractGatewayFilterFactory<C> extends AbstractConfigurable<C>
		implements GatewayFilterFactory<C> {

	@SuppressWarnings("unchecked")
	public AbstractGatewayFilterFactory() {
		super((Class<C>) Object.class);
	}

	public AbstractGatewayFilterFactory(Class<C> configClass) {
		super(configClass);
	}

	public static class NameConfig {

		private String name;

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}
	}
}

泛型参数C是配置类,从现有的AbstractGatewayFilterFactory或者GatewayFilterFactory的子类实现来看,配置类一般定义为公有静态内部类。

  1. 实现GatewayFilterFactory接口或者继承AbstractGatewayFilterFactory
  2. 对应的子类注册到Spring的容器
  3. 路由配置中的filters属性添加对应GatewayFilter配置,注意一下,过滤器名称由GatewayFilterFactory#name()决定。

实践

下面实现GatewayFilterFactory接口和继承AbstractGatewayFilterFactory抽象类两种方式都做了尝试。

实现GatewayFilterFactory接口

实现GatewayFilterFactory接口的时候,参考了SetRequestHeaderGatewayFilterFactory,为每个请求添加自定义的请求头。

代码语言:javascript
复制
@Component
public class CustomAddRequestHeaderGatewayFilterFactory implements
        GatewayFilterFactory<CustomAddRequestHeaderGatewayFilterFactory.CustomAddRequestHeaderConfig> {

    private final Class<CustomAddRequestHeaderConfig> configClass = CustomAddRequestHeaderConfig.class;

    @Override
    public List<String> shortcutFieldOrder() {
        return new ArrayList<>(Arrays.asList("headerName", "headerValue"));
    }

    @Override
    public GatewayFilter apply(CustomAddRequestHeaderConfig config) {
        return ((exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest().mutate().headers(httpHeaders -> {
                httpHeaders.set(config.getHeaderName(), config.getHeaderValue());
            }).build();
            return chain.filter(exchange.mutate().request(request).build());
        });
    }

    @Override
    public Class<CustomAddRequestHeaderConfig> getConfigClass() {
        return configClass;
    }

    @Override
    public CustomAddRequestHeaderConfig newConfig() {
        return BeanUtils.instantiateClass(this.configClass);
    }

    public static class CustomAddRequestHeaderConfig {

        private String headerName;
        private String headerValue;

        public String getHeaderName() {
            return headerName;
        }

        public void setHeaderName(String headerName) {
            this.headerName = headerName;
        }

        public String getHeaderValue() {
            return headerValue;
        }

        public void setHeaderValue(String headerValue) {
            this.headerValue = headerValue;
        }
    }
}

可以看到,其实最核心的功能操作是需要实现GatewayFilter apply(C config)方法,编写自定义的功能。注意这段Lambda表达式的逻辑:

代码语言:javascript
复制
return ((exchange, chain) -> {
    ServerHttpRequest request = exchange.getRequest().mutate().headers(httpHeaders -> {
        httpHeaders.set(config.getHeaderName(), config.getHeaderValue());
    }).build();
    return chain.filter(exchange.mutate().request(request).build());
});

其实,它可以简单理解为GatewayFilter接口的匿名实现。

application.yaml配置如下:

代码语言:javascript
复制
spring:
  cloud:
    gateway:
      routes:
        - id: custom_add_request_header_route
          uri: http://localhost:9091
          predicates:
            - Host=localhost:9090
          filters:
            - CustomAddRequestHeader=customHeaderName,customHeaderValue

为了配合测试,下游服务添加一个端点:

代码语言:javascript
复制
@GetMapping(value = "/customAddRequestHeader")
public ResponseEntity<String> customAddRequestHeader(@RequestHeader(name = "customHeaderName") String value) {
    return ResponseEntity.ok(value);
}
代码语言:javascript
复制
curl localhost:9090/order/customAddRequestHeader

// 响应
customHeaderValue

继承AbstractGatewayFilterFactory抽象类

继承AbstractGatewayFilterFactory的方式其实差不多,我们尝试做一个相对复杂的改造:对每一个请求成功(状态码为200)的响应,添加一个自定义的cookie和一个响应头。

代码语言:javascript
复制
@Component
public class CustomResponseGatewayFilterFactory extends
        AbstractGatewayFilterFactory<CustomResponseGatewayFilterFactory.Config> {

    public CustomResponseGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> {
            ServerHttpResponse response = exchange.getResponse();
            if (HttpStatus.OK.equals(response.getStatusCode())) {
                for (Map.Entry<String, String> entry : toMap(config.getCookie()).entrySet()) {
                    response.addCookie(ResponseCookie.from(entry.getKey(), entry.getValue()).build());
                }
                for (Map.Entry<String, String> entry : toMap(config.getHeader()).entrySet()) {
                    response.getHeaders().add(entry.getKey(), entry.getValue());
                }
                return chain.filter(exchange.mutate().response(response).build());
            } else {
                return chain.filter(exchange);
            }
        });
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList(NAME_KEY);
    }

    private static Map<String, String> toMap(String value) {
        String[] split = value.split("=");
        Map<String, String> map = new HashMap<>(8);
        map.put(split[0], split[1]);
        return map;
    }

    public static class Config {

        private String cookie;
        private String header;

        public String getCookie() {
            return cookie;
        }

        public void setCookie(String cookie) {
            this.cookie = cookie;
        }

        public String getHeader() {
            return header;
        }

        public void setHeader(String header) {
            this.header = header;
        }
    }
}

application.yaml配置文件如下:

代码语言:javascript
复制
spring:
  cloud:
    gateway:
      routes:
        - id: custom_response_route
          uri: http://localhost:9091
          predicates:
            - Host=localhost:9090
          filters:
            - name: CustomResponse
              args:
                cookie: customCookieName=customCookieValue
                header: customHeaderName=customHeaderValue

这里注意,filters集合下的name属性是必须的,指向AbstractGatewayFilterFactory实现类的name()方法,args属性是用于指定装配到Config类的属性。

代码语言:javascript
复制
curl localhost:9090/order/remote

// 响应头如下
customHeaderName: customHeaderValue
Content-Type: text/plain;charset=UTF-8
Content-Length: 6
Date: Sun, 05 May 2019 11:06:35 GMT
set-cookie: customCookieName=customCookieValue

小结

自定义GatewayFilter允许我们很灵活地扩展过滤器,并且对于请求或者响应添加自定义的一些属性或者判断逻辑。GatewayFilter不是全局生效的特性,使得我们在编写路由配置的时候可以灵活组合多个已经编写好的GatewayFilter实例的功能。

(c-1-d e-a-20190505)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年5月5日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
聊聊spring cloud gateway的GatewayFilter
本文主要研究一下spring cloud gateway的GatewayFilter
code4it
2018/09/17
2.7K0
聊聊spring cloud gateway的PrefixPath及StripPrefix功能
本文主要研究一下spring cloud gateway的PrefixPath及StripPrefix功能
code4it
2018/09/17
4.6K0
Gateway 自定义过滤器
Spring Cloud Gateway虽然自带有许多实用的GatewayFilter Factory、Gateway Filter、Global Filter,但是在很多业务情景下仍然需要自定义过滤器。实现一些自定义操作,满足业务需求。所以自定义过滤器就显得非常有必要。本文分表介绍自定义Gateway Filter、自定义Global Filter、自定义Gateway Filter Factory。
BUG弄潮儿
2020/12/17
2.4K0
spring cloud gateway之filter篇
在上一篇文章详细的介绍了Gateway的Predict,Predict决定了请求由哪一个路由处理,在路由处理之前,需要经过“pre”类型的过滤器处理,处理返回响应之后,可以由“post”类型的过滤器处理。
方志朋
2019/06/21
3.1K0
spring cloud gateway之filter篇
Route加载流程
网关服务核心功能是路由转发,即将接收的请求如何正确的路由到下层具体的服务模块。下面分析下这些路由信息构建的流程。
Reactor2020
2023/03/22
1K0
Route加载流程
SpringCloud 2.x学习笔记:15、Spring Cloud Gateway之Filter过滤器(Greenwich版本)
AddRequestHeaderGatewayFilterFactory的源码
程裕强
2019/07/02
1K0
SpringCloud 2.x学习笔记:15、Spring Cloud Gateway之Filter过滤器(Greenwich版本)
SpringCloud系列之自定义GatewayFilterFactory
新增SpringBoot Initializer项目:New Module->Spring Initializer,选择jdk版本,至少jdk8
SmileNicky
2021/12/17
1.4K0
SpringCloud系列之自定义GatewayFilterFactory
spring cloud gateway的stripPrefix配置
本文主要研究下spring cloud gateway的stripPrefix配置
code4it
2018/09/17
5.6K0
SpringCloud Gateway中你不知道的骚操作
之前的几篇文章中,我们已经提到了如何使用SpringCloud Gateway,那几篇文章的内容已经足够做普通项目使用了,但是如果你想深入了解这个东西,或者说是看完这篇文章你用起来跟普通人就完全不是一个等级的了
Java学习录
2019/12/03
2K0
Spring Cloud之服务入口Gateway之自定义过滤器
在 Spring Cloud Gateway 中,过滤器是用于对请求和响应进行预处理和后处理的组件。通过自定义过滤器,您可以控制请求的生命周期,做如日志记录、身份认证、限流、重试、请求改写等操作。Spring Cloud Gateway 允许您创建 Global Filters(全局过滤器)和 Gateway Filters(局部过滤器),它们可以在不同的场景下提供灵活的定制。
用户3672714
2025/08/02
4710
Spring Cloud Gateway-使用自定义过滤器通过Hystrix实现降级处理
在微服务架构中,下游依赖出现问题如果上游调用方不做请求降级处理,下游的异常依赖没有被隔离,很有可能出现因为一两个服务或者小到一两个接口异常导致上游所有服务不可用,甚至影响整个业务线。请求降级处理目前比较主流的依然是Netfilx出品的Hystrix。Hystrix的工作原理是:
Throwable
2020/06/23
4.3K0
聊聊spring cloud gateway的PreserveHostHeaderGatewayFilter
本文主要研究下spring cloud gateway的PreserveHostHeaderGatewayFilter
code4it
2018/09/17
1.6K0
spring cloud gateway集成hystrix实战
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java
code4it
2018/09/17
4K0
Spring Cloud Gateway 之 AddRequestHeader GatewayFilter Factory
今天我们来学习下GatewayFilter Factory,中文解释就是过滤器工厂。
猿天地
2018/10/23
1.8K0
Spring Cloud Gateway 之 Filter
网关经常需要对路由请求进行过滤,进行一些操作,如鉴权之后构造头部之类的,过滤的种类很多,如增加请求头、增加请求 参数 、增加响应头和断路器等等功能,这就用到了Spring Cloud Gateway 的 Filter。
程序员果果
2019/05/21
1.3K0
Spring Cloud 之 Gateway.
Zuul 基于servlet 2.5 (works with 3.x),使用阻塞API。它不支持任何长期的连接,如websocket。
JMCui
2019/07/29
1.4K0
Spring Cloud Gateway 读取、修改请求体(解决request body内容被截断)
微服务架构,在网关服务里拦截每个请求,进行日志信息记录与管理,发现当请求体过长时,只能获取到一部分body,查看拦截过滤器,发现Spring Cloud Gateway是基于reactor-core.jar进行请求数据的操作,获取body内容时,用到了reactor-core.jar的Flux,即一个包含0-N个DataBuffer类型元素的同步序列。
一滴水的眼泪
2020/09/24
5.4K2
Spring Cloud Gateway 读取、修改请求体(解决request body内容被截断)
服务网关Spring Cloud Gateway
Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul网关。网关作为流量的,在微服务系统中有着非常作用,网关常见的功能有路由转发、权限校验、限流控制等作用。
chenchenchen
2022/01/05
1.1K0
服务网关Spring Cloud Gateway
Spring Cloud Gateway简单使用
Gateway网关是我们服务的守门神,所有微服务的统一入口。Spring Cloud Gateway 是 Spring Cloud的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。在Gateway之前,SpringCloud并不自己开发网关,可能是觉得Netflflix公司的Zuul不行吧,然后自己就写了一个,也是替代Netflflix Zuul。其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
ha_lydms
2023/08/10
1.1K0
Spring Cloud Gateway简单使用
​Java | Spring Cloud Gateway 使用和一些实现细节
所谓的API网关,就是指系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、路由转发等。
双鬼带单
2021/07/20
2.2K0
相关推荐
聊聊spring cloud gateway的GatewayFilter
更多 >
目录
  • 前提
  • 如何自定义GatewayFilter
  • 实践
    • 实现GatewayFilterFactory接口
    • 继承AbstractGatewayFilterFactory抽象类
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
首页
学习
活动
专区
圈层
工具
MCP广场
首页
学习
活动
专区
圈层
工具
MCP广场