1 使用

  • 组件
    • Spring 5
    • Spring Boot 2
    • Spring WebFlux
      • Netty
  • 功能
    • 鉴权授权
    • 系统监控
    • 反向代理
    • 流量控制
    • 日志管理
    • 安全管理
    • 协议转换
    • 服务注册
    • 服务发现
    • 业务缓存
    • 业务隔离

Spring Cloud Gateway 需要 Spring Boot 和 Spring Webflux 提供的 Netty 运行时。它不能在传统的Servlet 容器中工作,也不能构建成WAR包运行。

  1. # 打开网关功能
  2. spring.cloud.gateway.enabled=true
# 添加依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

2 概念

Route(路由):路由是构建网关的基本模块,它由 ID、目标 URI、一系列的断言和过滤器组成,如果断言为 true 则匹配该路由。
Predicate(断言):参考的是 Java8 中的 java.util.function.Predicate。开发人员可以匹配 HTTP 请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由。
Filter(路由):框架提供的GatewayFilter,可以在请求被路由之前或之后对请求进行修改。

3 工作机制

官方文档 - 图1
客户端向网关发出请求。如果网关处理程序映射确定请求与路由匹配,则将其发送到网关 Web 处理程序。该处理程序通过特定于请求的过滤器链来运行请求。用虚线划分过滤器的原因是,过滤器可以在发送代理请求之前和之后运行逻辑。执行所有“前置”过滤器逻辑。然后发出代理请求。发出代理请求后,将运行“后置”过滤器逻辑。

4 配置路由

4.2 配置文件

# 静态路由
spring.cloud.gateway.routes[0].id=route-sina
spring.cloud.gateway.routes[0].uri=https://www.sina.com.cn/
spring.cloud.gateway.routes[0].predicates[0]=Path=/sina/**
spring.cloud.gateway.routes[0].order=1

# 动态路由
spring.cloud.gateway.routes[1].id=route-service-name
spring.cloud.gateway.routes[1].uri=lb:/micro-service-name 服务实例
spring.cloud.gateway.routes[1].predicates[0]=Path=/name/**
spring.cloud.gateway.routes[1].order=1

4.2 代码配置

@Configuration
public class RouteConfig {

    @Bean
    public RouteLocator routes(RouteLocatorBuilder builder) {
        return builder.routes().
                route("route-cnblogs", r -> r.path("/cnblogs/**")
                        .uri("https://www.cnblogs.com/")
                        .order(1))
            .build();
    }

}

5 路由断言

5.1 AfterRoutePredicateFactory

匹配指定日期时间之后发生的请求

5.1.1 配置

spring.cloud.gateway.routes[0].predicates[1]=
After=2021-12-24T14:19:43.863+08:00[Asia/Shanghai]

5.1.2 关键代码

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                final ZonedDateTime now = ZonedDateTime.now();
                return now.isAfter(config.getDatetime());
            }
    }

5.2 BeforeRoutePredicateFactory

匹配指定日期时间之前发生的请求

5.2.1 配置

spring.cloud.gateway.routes[0].predicates[2]=
Before=2021-12-24T14:19:43.863+08:00[Asia/Shanghai]

5.2.2 关键代码

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                final ZonedDateTime now = ZonedDateTime.now();
                return now.isBefore(config.getDatetime());
            }
    }

5.3 BetweenRoutePredicateFactory

在指定时间内发生的请求

5.3.1 配置

spring.cloud.gateway.routes[0].predicates[3]=
Between=2021-12-24T14:19:43.863+08:00[Asia/Shanghai],2021-12-24T14:28:43.863+08:00[Asia/Shanghai]

5.3.2 关键代码

    public Predicate<ServerWebExchange> apply(Config config) {
        Assert.isTrue(config.getDatetime1().isBefore(config.getDatetime2()),
                config.getDatetime1() + " must be before " + config.getDatetime2());

        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                final ZonedDateTime now = ZonedDateTime.now();
                return now.isAfter(config.getDatetime1())
                        && now.isBefore(config.getDatetime2());
            }
    }

5.4 CookieRoutePredicateFactory

Cookie 路由断言工厂接受两个参数,Cookie 名称和 regexp (一个 Java 正则表达式)。该谓词匹配具有给定名称且其值与正则表达式匹配的 cookie。

5.4.1 配置

spring.cloud.gateway.routes[0].predicates[2]=Cookie=auth-token,^1{n}$

5.4.2 关键代码

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                List<HttpCookie> cookies = exchange.getRequest().getCookies()
                        .get(config.name);
                if (cookies == null) {
                    return false;
                }
                for (HttpCookie cookie : cookies) {
                    if (cookie.getValue().matches(config.regexp)) {
                        return true;
                    }
                }
                return false;
            }
    }

5.5 HeaderRoutePredicateFactory

Header 路由断言工厂接受两个参数: Header名称和 regexp (一个 Java 正则表达式)。与具有给定名称的请求头匹配,该请求头的值与正则表达式匹配。

5.5.1 配置
spring.cloud.gateway.routes[0].predicates[2]=Header=auth-token,[a-h]{6}

5.5.2 关键代码

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        boolean hasRegex = !StringUtils.isEmpty(config.regexp);

        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                List<String> values = exchange.getRequest().getHeaders()
                        .getOrDefault(config.header, Collections.emptyList());
                if (values.isEmpty()) {
                    return false;
                }
                // values is now guaranteed to not be empty
                if (hasRegex) {
                    // check if a header value matches
                    return values.stream()
                            .anyMatch(value -> value.matches(config.regexp));
                }
                return true;
            }
        };
    }

5.6 HostRoutePredicateFactory

Host 路由断言工厂接受一个参数: 主机名列表。支持Ant分割模式,匹配Host请求头。

5.6.1 配置

spring.cloud.gateway.routes[0].predicates[3]=Host=127.0.0.1:9010,**.evan.com

5.6.2 关键diamante

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                String host = exchange.getRequest().getHeaders().getFirst("Host");
                Optional<String> optionalPattern = config.getPatterns().stream()
                        .filter(pattern -> pathMatcher.match(pattern, host)).findFirst();

                if (optionalPattern.isPresent()) {
                    Map<String, String> variables = pathMatcher
                            .extractUriTemplateVariables(optionalPattern.get(), host);
                    ServerWebExchangeUtils.putUriTemplateVariables(exchange, variables);
                    return true;
                }

                return false;
            }
        };
    }

5.7 MethodRoutePredicateFactory

Method 路由断言工厂接受一个参数: 支持的请求方式,多个方式逗号隔开

5.7.1 配置

spring.cloud.gateway.routes[0].predicates[4]=Method=GET,POST

5.7.2 关键代码

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                HttpMethod requestMethod = exchange.getRequest().getMethod();
                return stream(config.getMethods())
                        .anyMatch(httpMethod -> httpMethod == requestMethod);
            }
        };
    }

5.8 PathRoutePredicateFactory

重要

5.8.1 配置

spring.cloud.gateway.routes[0].predicates[0]=Path=/sina/**

5.8.2 关键代码

org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory

5.9 QueryRoutePredicateFactory

Query 路由断言工厂接受两个参数: 请求参数和一个可选的regexp表达式

5.9.1 配置

spring.cloud.gateway.routes[0].predicates[5]=Query=name,xiao[1-9]

5.9.2 关键代码

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                if (!StringUtils.hasText(config.regexp)) {
                    // check existence of header
                    return exchange.getRequest().getQueryParams()
                            .containsKey(config.param);
                }

                List<String> values = exchange.getRequest().getQueryParams()
                        .get(config.param);
                if (values == null) {
                    return false;
                }
                for (String value : values) {
                    if (value != null && value.matches(config.regexp)) {
                        return true;
                    }
                }
                return false;
            }

        };
    }

5.10 RemoteAddrRoutePredicateFactory

5.10.1 配置

spring.cloud.gateway.routes[0].predicates[6]=RemoteAddr=192.168.1.1/24

5.10.2 关键代码

5.11 WeightRoutePredicateFactory

Weight 路由断言工厂接受两个参数: 分组1和权重1

5.12 ReadBodyRoutePredicateFactory

5.13 CloudFoundryRouteServiceRoutePredicateFactory

6 路由过滤

6.1 AddRequestHeaderGatewayFilterFactory

添加请求头
AddRequestHeader=X-Request-red, blue

    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange,
                    GatewayFilterChain chain) {
                String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
                ServerHttpRequest request = exchange.getRequest().mutate()
                        .header(config.getName(), value).build();
                return chain.filter(exchange.mutate().request(request).build());
            }
        };
    }

6.2 AddRequestParameterGatewayFilterFactory

添加请求Query参数
AddRequestParameter=red, blue

6.3 AddResponseHeaderGatewayFilterFactory

添加响应头
AddResponseHeader=X-Response-Red, Blue

    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange,
                    GatewayFilterChain chain) {
                String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
                exchange.getResponse().getHeaders().add(config.getName(), value);

                return chain.filter(exchange);
            }
        };
    }

6.4 DedupeResponseHeaderGatewayFilterFactory

去除重复的响应头
DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

6.5 FallbackHeadersGatewayFilterFactory

Hystrix熔断器的支持

6.6 HystrixGatewayFilterFactory

Hystrix熔断器的支持

6.7 MapRequestHeaderGatewayFilterFactory

请求头重命名
MapRequestHeader=Blue, X-Request-Red

@Override
    public GatewayFilter apply(MapRequestHeaderGatewayFilterFactory.Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange,
                    GatewayFilterChain chain) {
                if (!exchange.getRequest().getHeaders()
                        .containsKey(config.getFromHeader())) {
                    return chain.filter(exchange);
                }
                List<String> headerValues = exchange.getRequest().getHeaders()
                        .get(config.getFromHeader());

                ServerHttpRequest request = exchange.getRequest().mutate()
                        .headers(i -> i.addAll(config.getToHeader(), headerValues))
                        .build();

                return chain.filter(exchange.mutate().request(request).build());
            }
        };
    }

6.8 PrefixPathGatewayFilterFactory

请求URI增加前缀
PrefixPath=/mypath

6.9 PreserveHostHeaderGatewayFilterFactory

PreserveHostHeader

6.10 RedirectToGatewayFilterFactory

RedirectTo=302, https://acme.org

    public GatewayFilter apply(String statusString, String urlString) {
        HttpStatusHolder httpStatus = HttpStatusHolder.parse(statusString);
        Assert.isTrue(httpStatus.is3xxRedirection(),
                "status must be a 3xx code, but was " + statusString);
        final URI url = URI.create(urlString);
        return apply(httpStatus, url);
    }
    public GatewayFilter apply(HttpStatusHolder httpStatus, URI uri) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange,
                    GatewayFilterChain chain) {
                if (!exchange.getResponse().isCommitted()) {
                    setResponseStatus(exchange, httpStatus);

                    final ServerHttpResponse response = exchange.getResponse();
                    response.getHeaders().set(HttpHeaders.LOCATION, uri.toString());
                    return response.setComplete();
                }
                return Mono.empty();
            }
        };
    }

6.11 RemoveRequestHeaderGatewayFilterFactory

删除请求头
RemoveRequestHeader=X-Request-Foo

6.12 RemoveRequestParameterGatewayFilterFactory

删除请求参数
RemoveRequestParameter=red

6.13 RemoveResponseHeaderGatewayFilterFactory

删除响应头
RemoveResponseHeader=X-Response-Foo

6.14 RequestHeaderSizeGatewayFilterFactory

6.15 RequestHeaderToRequestUriGatewayFilterFactory

6.16 RequestRateLimiterGatewayFilterFactory

请求限流

6.17 RequestSizeGatewayFilterFactory

6.18 RetryGatewayFilterFactory

6.19 RewriteLocationResponseHeaderGatewayFilterFactory

6.20 RewritePathGatewayFilterFactory

重写请求路径
RewritePath=/red(?/?.*), ${segment}

6.21 SaveSessionGatewayFilterFactory

6.22 SecureHeadersGatewayFilterFactory

6.23 SetPathGatewayFilterFactory

6.24 SetResponseHeaderGatewayFilterFactory

6.25 SetRequestHeaderGatewayFilterFactory

6.26 SetStatusGatewayFilterFactory

6.27 SpringCloudCircuitBreakerFilterFactory

6.28 SpringCloudCircuitBreakerHystrixFilterFactory

6.29 SpringCloudCircuitBreakerResilience4JFilterFactory

6.30 StripPrefixGatewayFilterFactory

7 全局过滤器

7.1 GlobalFilter

@Configuration
public class GlobalFilterConfig {
    @Bean
    public FirstGlobalFilter firstGlobalFilter(){
        return new FirstGlobalFilter();
    }
}
public class FirstGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("pre FirstGlobalFilter");

        return chain.filter(exchange).then(Mono.fromRunnable(new Runnable() {
            @Override
            public void run() {
                log.info("post FirstGlobalFilter");
            }
        }));
    }
    @Override
    public int getOrder() {
        // 指定优先级
        return 0;
    }
}

7.2 ForwardRoutingFilter

服务内请求转发
forward的请求

    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI requestUrl = (URI)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        String scheme = requestUrl.getScheme();
        if (!ServerWebExchangeUtils.isAlreadyRouted(exchange) && "forward".equals(scheme)) {
            if (log.isTraceEnabled()) {
                log.trace("Forwarding to URI: " + requestUrl);
            }

            return this.getDispatcherHandler().handle(exchange);
        } else {
            return chain.filter(exchange);
        }
    }

7.3 LoadBalancerClientFilter

负载均衡

    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
        String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
        if (url == null
                || (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
            return chain.filter(exchange);
        }
        // preserve the original url
        addOriginalRequestUrl(exchange, url);
        // 选择策略实现类选择一个路由节点
        final ServiceInstance instance = choose(exchange);

        if (instance == null) {
            throw NotFoundException.create(properties.isUse404(),
                    "Unable to find instance for " + url.getHost());
        }

        URI uri = exchange.getRequest().getURI();

        // if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,
        // if the loadbalancer doesn't provide one.
        String overrideScheme = instance.isSecure() ? "https" : "http";
        if (schemePrefix != null) {
            overrideScheme = url.getScheme();
        }
        URI requestUrl = loadBalancer.reconstructURI(
                new DelegatingServiceInstance(instance, overrideScheme), uri);
        if (log.isTraceEnabled()) {
            log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
        }
        exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
        return chain.filter(exchange);
    }
    protected ServiceInstance choose(ServerWebExchange exchange) {
        return loadBalancer.choose(
                ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost());
    }

7.4 ReactiveLoadBalancerClientFilter

同上
Spring 官方提供的负责均衡过滤器

  • spring.cloud.loadbalancer.ribbon.enabled 关闭ribbon负载均衡算法
  • 增加依赖

             <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-loadbalancer</artifactId>
          </dependency>
    
  • 提供的负载均衡算法

    • RoundRobinLoadBalancer 随机
    • 自定义实现参考

      7.5 NettyRoutingFilter

      使用Netty的 HttpClient 转发http、https请求

      7.6 NettyWriteResponseFilter

      将代理的响应返回客户端

      7.7 RouteToRequestUrlFilter

      根据匹配的 Route,计算请求的地址

      7.8 WebsocketRoutingFilter

      Websocket路由网关过滤器。其根据ws://,wss://前缀(Scheme)过滤处理,代理后端Websocket服务,提供给客户端连接

      public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
         changeSchemeIfIsWebSocketUpgrade(exchange);
         // 获取请求
         URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
         String scheme = requestUrl.getScheme();
         if (isAlreadyRouted(exchange)
                 || (!"ws".equals(scheme) && !"wss".equals(scheme))) {
             return chain.filter(exchange);
         }
         // 设置请求已经被路由
         setAlreadyRouted(exchange);
      
         HttpHeaders headers = exchange.getRequest().getHeaders();
         HttpHeaders filtered = filterRequest(getHeadersFilters(), exchange);
         List<String> protocols = headers.get(SEC_WEBSOCKET_PROTOCOL);
         if (protocols != null) {
             protocols = headers.get(SEC_WEBSOCKET_PROTOCOL).stream().flatMap(
                     header -> Arrays.stream(commaDelimitedListToStringArray(header)))
                     .map(String::trim).collect(Collectors.toList());
         }
         // 请求分发处理
         return this.webSocketService.handleRequest(exchange, new ProxyWebSocketHandler(
                 requestUrl, this.webSocketClient, filtered, protocols));
      }
      

      7.9 GatewayMetricsFilter

      网关指标收集
      spring.cloud.gateway.metrics.enabled=true
      添加依赖

         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-actuator</artifactId>
         </dependency>
      
      public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
         Sample sample = Timer.start(meterRegistry);
      
         return chain.filter(exchange)
                 .doOnSuccess(aVoid -> endTimerRespectingCommit(exchange, sample))
                 .doOnError(throwable -> endTimerRespectingCommit(exchange, sample));
      }
      

      8 Http请求头过滤器

      public interface HttpHeadersFilter {
      static HttpHeaders filterRequest(List<HttpHeadersFilter> filters,
             ServerWebExchange exchange) {
         HttpHeaders headers = exchange.getRequest().getHeaders();
         return filter(filters, headers, exchange, Type.REQUEST);
      }
      static HttpHeaders filter(List<HttpHeadersFilter> filters, HttpHeaders input,
             ServerWebExchange exchange, Type type) {
         HttpHeaders response = input;
         if (filters != null) {
             HttpHeaders reduce = filters.stream()
                     .filter(headersFilter -> headersFilter.supports(type)).reduce(input,
                             (headers, filter) -> filter.filter(headers, exchange),
                             (httpHeaders, httpHeaders2) -> {
                                 httpHeaders.addAll(httpHeaders2);
                                 return httpHeaders;
                             });
             return reduce;
         }
         return response;
      }
      
      /**
      * Filters a set of Http Headers.
      * @param input Http Headers
      * @param exchange a {@link ServerWebExchange} that should be filtered
      * @return filtered Http Headers
      */
      HttpHeaders filter(HttpHeaders input, ServerWebExchange exchange);
      default boolean supports(Type type) {
         return type.equals(Type.REQUEST);
      }
      enum Type {
         REQUEST, RESPONSE
      }
      }
      

      8.1 ForwardedHeadersFilter

      添加转发请求头

      8.2 RemoveHopByHopHeadersFilter

      删除的标头的默认IETF请求头。

      8.3 XForwardedHeadersFilter

      增加X-Forwarded-For、X-Forwarded-Host、X-Forwarded-Port和X-Forwarded-Proto头部。代理转发时用以自定义的头部信息向下游传递。

      9 TLS SSL

      10 配置

      10.1 核心类

  • 路由信息定义 org.springframework.cloud.gateway.route.RouteDefinition

  • 路由信息加载接口 org.springframework.cloud.gateway.route.RouteDefinitionLocator

    • org.springframework.cloud.gateway.config.PropertiesRouteDefinitionLocator
    • org.springframework.cloud.gateway.route.CachingRouteDefinitionLocator

      11 路由元数据配置

  • 配置

    spring.cloud.gateway.routes[0].metadata.name=route-sina
    
  • 获取数据

    Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
    route.getMetadata();
    route.getMetadata(someKey);
    

    12 HTTP超时设置

    12.1 全局配置

    spring.cloud.gateway.httpclient.connect-timeout=1000
    spring.cloud.gateway.httpclient.response-timeout=5s
    

    12.2 路由配置

    spring.cloud.gateway.routes[0].metadata.connect-timeout=1000
    spring.cloud.gateway.routes[0].metadata.response-timeout=5000
    

    12.3 Fluent API

    12.4 动态服务

    spring.cloud.gateway.discovery.locator.enabled=true
    

    DiscoveryClient 默认配置
    /serviceId/
    serviceId来自DiscoveryClient 的服务ID

13 Netty请求方位日志

开启Netty请求日志
-Dreactor.netty.http.server.accessLogEnabled=true

14 跨域设置

spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedOrigins=https://docs.spring.io
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedMethods[0]=GET

15 监控

16 故障排除

16.1 日志

logging.level.org.springframework.cloud.gateway=debug
logging.level.org.springframework.http.server.reactive=debug
logging.level.org.springframework.web.reactive=debug
logging.level.org.springframework.boot.autoconfigure.web=info
logging.level.reactor.netty=info
logging.level.redisratelimiter=info

16.2 请求日志

spring.cloud.gateway.httpserver.wiretap=true
spring.cloud.gateway.httpclient.wiretap=true

17 开发者指南

17.1 自定义RoutePredicateFactory

public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.Config> {

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

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        // grab configuration from Config object
        return exchange -> {
            //grab the request
            ServerHttpRequest request = exchange.getRequest();
            //take information from the request to see if it
            //matches configuration.
            return matches(config, request);
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

17.2 自定义GatewayFilterFactory

public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.Config> {

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

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        // grab configuration from Config object
        return exchange -> {
            //grab the request
            ServerHttpRequest request = exchange.getRequest();
            //take information from the request to see if it
            //matches configuration.
            return matches(config, request);
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}
public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {

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

    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                ServerHttpResponse response = exchange.getResponse();
                //Manipulate the response in some way
            }));
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

17.3 自定义GlobalFilter

@Bean
public GlobalFilter customGlobalFilter() {
    return (exchange, chain) -> exchange.getPrincipal()
        .map(Principal::getName)
        .defaultIfEmpty("Default User")
        .map(userName -> {
          //adds header to proxied request
          exchange.getRequest().mutate().header("CUSTOM-REQUEST-HEADER", userName).build();
          return exchange;
        })
        .flatMap(chain::filter);
}

@Bean
public GlobalFilter customGlobalPostFilter() {
    return (exchange, chain) -> chain.filter(exchange)
        .then(Mono.just(exchange))
        .map(serverWebExchange -> {
          //adds header to response
          serverWebExchange.getResponse().getHeaders().set("CUSTOM-RESPONSE-HEADER",
              HttpStatus.OK.equals(serverWebExchange.getResponse().getStatusCode()) ? "It worked": "It did not work");
          return serverWebExchange;
        })
        .then();
}