SpringCloud 12 —— 网关之Gateway (中) 过滤器

过滤器

目前GatewayFilter工厂的内建实现如下:

ID类名类型功能
StripPrefixStripPrefixGatewayFilterFactorypre移除请求URL路径的第一部分,例如原始请求路径是/order/query,处理后是/query
SetStatusSetStatusGatewayFilterFactorypost设置请求响应的状态码,会从org.springframework.http.HttpStatus中解析
SetResponseHeaderSetResponseHeaderGatewayFilterFactorypost设置(添加)请求响应的响应头
SetRequestHeaderSetRequestHeaderGatewayFilterFactorypre设置(添加)请求头
SetPathSetPathGatewayFilterFactorypre设置(覆盖)请求路径
SecureHeaderSecureHeadersGatewayFilterFactorypre设置安全相关的请求头,见SecureHeadersProperties
SaveSessionSaveSessionGatewayFilterFactorypre保存WebSession
RewriteResponseHeaderRewriteResponseHeaderGatewayFilterFactorypost重新响应头
RewritePathRewritePathGatewayFilterFactorypre重写请求路径
RetryRetryGatewayFilterFactorypre基于条件对请求进行重试
RequestSizeRequestSizeGatewayFilterFactorypre限制请求的大小,单位是byte,超过设定值返回413 Payload Too Large
RequestRateLimiterRequestRateLimiterGatewayFilterFactorypre限流
RequestHeaderToRequestUriRequestHeaderToRequestUriGatewayFilterFactorypre通过请求头的值改变请求URL
RemoveResponseHeaderRemoveResponseHeaderGatewayFilterFactorypost移除配置的响应头
RemoveRequestHeaderRemoveRequestHeaderGatewayFilterFactorypre移除配置的请求头
RedirectToRedirectToGatewayFilterFactorypre重定向,需要指定HTTP状态码和重定向URL
PreserveHostHeaderPreserveHostHeaderGatewayFilterFactorypre设置请求携带的属性preserveHostHeader为true
PrefixPathPrefixPathGatewayFilterFactorypre请求路径添加前置路径
HystrixHystrixGatewayFilterFactorypre整合Hystrix
FallbackHeadersFallbackHeadersGatewayFilterFactorypreHystrix执行如果命中降级逻辑允许通过请求头携带异常明细信息
AddResponseHeaderAddResponseHeaderGatewayFilterFactorypost添加响应头
AddRequestParameterAddRequestParameterGatewayFilterFactorypre添加请求参数,仅仅限于URL的Query参数
AddRequestHeaderAddRequestHeaderGatewayFilterFactorypre添加请求头

这些filter的执行顺序和配置定义的顺序是有关系的

过滤器 MapRequestHeader

MapRequestHeader GatewayFilter 工厂采用两个参数:fromHeader 和 toHeader.

应用配置

这里我们继续使用上一节的项目模块。配置中设置谓词的After 类型,如果不设置谓词会报错,我们MapRequestHeader的两个参数分别设置值,最终第一个参数的值会拼在第二个参数后面。如果需要继续请求,那么在后面的服务接收到的Header值就会是新拼接的数据值。添加配置:

---
spring:
  cloud:
    gateway:
      routes:
        - id: map_request_header_route
          uri: lb://ribbon-server
          predicates:
            - After=2020-05-05T13:20:14.455+08:00[Asia/Shanghai]
          filters:
            - MapRequestHeader=Blue, X-Request-Red
  profiles: map_request_header_route

将profiles.active改为map_request_header_route

说明: fromHeader 和 toHeader 在上例中分别为 Blue 和 X-Request-Red .

在ribbon-server 服务端添加接收方法

    /**
     * 配合gateway
     * @return
     * @throws InterruptedException
     */
    @GetMapping("/header")
    public String header(@RequestHeader(value = "Host", required = false)  String host,
                         @RequestHeader(value = "Blue", required = false)  String blue,
                         @RequestHeader(value = "X-Request-Red", required = false)  String requestRed) {

        StringBuilder sp=new StringBuilder();
        if(StrUtil.isNotBlank(host)){
            sp.append("Host:").append(host).append(System.lineSeparator());
        }
        if(StrUtil.isNotBlank(host)){
            sp.append("Blue:").append(blue).append(System.lineSeparator());
        }
        if(StrUtil.isNotBlank(host)){
            sp.append("X-Request-Red:").append(requestRed).append(System.lineSeparator());
        }
        return sp.toString();
    }

启动应用访问127.0.0.1:8699/user/header测试

过滤器 StripPrefix

StripPrefix GatewayFilter工厂采用一个参数:part, 这个参数在请求转发到下游之前去除路径的前part部分

StripPrefix可以接受一个非负整数,对应的具体实现是StripPrefixGatewayFilterFactory,从名字就可以看出它的作用是去掉前缀的,那个整数即对应层数。

添加配置

---
spring:
  cloud:
    gateway:
      routes:
        - id: strippath_route
          uri: lb://ribbon-server
          predicates:
            - Path=/gateway/**
          filters:
            - StripPrefix=1 #去掉Path的第一部分也就是/gateway
  profiles: strippath_route

启动测试,我们通过 Spring Cloud Gateway 访问/gateway/user/1,那么当网关服务向后转发请求时,会去掉/gateway

过滤器 Prefix

该PrefixPath、GatewayFilter工厂采用单个prefix参数

添加配置

下面配置中,我们设置了一个路由前缀,会在我们输入的路径前面拼上我们设置的前缀,比如/1将向发送请求/user/1。

---
spring:
  cloud:
    gateway:
      routes:
        - id: prefixpath_route
          uri: lb://ribbon-server
          predicates:
            - After=2020-05-05T13:20:14.455+08:00[Asia/Shanghai]
          filters:
            - PrefixPath= /user #前缀路由,所有请求会加上前缀/user
  profiles: prefixpath_route

访问127.0.0.1:8699/1进行测试

PrefixPathGatewayFilterFactory源码分析

刚开始初始化的时候会设置网关是否已设置前缀gatewayAlreadyPrefixed为false,如果已经设置,就会以设置的为主。
修改gatewayAlreadyPrefixed的状态为true,并修改url的地址加上config.prefix中的值,config.prefix的值可以图片。
修改完之后重新构建ServerHttpRequest,之后交给NettyRoutingFilter执行

@Override
public GatewayFilter apply(Config config) {
   return new GatewayFilter() {
      @Override
      public Mono<Void> filter(ServerWebExchange exchange,
            GatewayFilterChain chain) {
         boolean alreadyPrefixed = exchange
               .getAttributeOrDefault(GATEWAY_ALREADY_PREFIXED_ATTR, false);
         if (alreadyPrefixed) {
            return chain.filter(exchange);
         }
         exchange.getAttributes().put(GATEWAY_ALREADY_PREFIXED_ATTR, true);

         ServerHttpRequest req = exchange.getRequest();
         addOriginalRequestUrl(exchange, req.getURI());
         String newPath = config.prefix + req.getURI().getRawPath();

         ServerHttpRequest request = req.mutate().path(newPath).build();

         exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI());

         if (log.isTraceEnabled()) {
            log.trace("Prefixed URI with: " + config.prefix + " -> "
                  + request.getURI());
         }

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

      @Override
      public String toString() {
         return filterToStringCreator(PrefixPathGatewayFilterFactory.this)
               .append("prefix", config.getPrefix()).toString();
      }
   };
}

过滤器 PreserveHostHeader

PreserveHostHeader GatewayFilter Factory没有参数。 此过滤器设置路由过滤器将检查的请求属性,以确定是否应发送原始主机头,而不是http客户端确定的主机头

添加配置

spring:
  cloud:
    gateway:
      routes:
        - id: preserve_host_route
          uri: lb://ribbon-server
          predicates:
            - After=2020-05-05T13:20:14.455+08:00[Asia/Shanghai]
          filters:
            - PreserveHostHeader
  profiles: preserve_host_route

PreserveHostHeaderGatewayFilterFactory 源码

这个filter就往exchange添加PRESERVE_HOST_HEADER_ATTRIBUTE,设置为true