Spring Gateway 全局过滤器 Global Filters

原文档地址:点这里

6. Global Filters

GlobalFilter接口和GatewayFilter接口都只有一个相同的方法,这些特殊的过滤器可以有条件的应用于所有的路由。(这些接口和用法在以后的版本中可能会被修改)。

6.1 Combined Global Filter and GatewayFilter Ordering(过滤器的执行顺序)

当一个请求到达一个Gateway的路由时,Filtering Web Handler会加载所有的GlobalFilter实例以及这个路由上配置的所有的GatewayFilter过滤器,然后组成一个完整的过滤链。这个过滤链中过滤器使用org.springframework.core.Ordered接口进行排序,可以通过实现Ordered接口中的getOrder()方法或直接使用@Order注解修改过滤器的顺序。

由于Spring Cloud Gateway分开执行“pre”和“post”的过滤器,(可以参考前面讲Gateway如何工作的章节),因此,优先级高的过滤器将先执行“pre”类型的过滤器,最后执行“post”类型的的过滤器,如下面代码所示:

@Bean
@Order(-1)
public GlobalFilter a() {
    return (exchange, chain) -> {
        log.info("first pre filter");
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            log.info("third post filter");
        }));
    };
}

@Bean
@Order(0)
public GlobalFilter b() {
    return (exchange, chain) -> {
        log.info("second pre filter");
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            log.info("second post filter");
        }));
    };
}

@Bean
@Order(1)
public GlobalFilter c() {
    return (exchange, chain) -> {
        log.info("third pre filter");
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            log.info("first post filter");
        }));
    };
}

从上面的代码可以看出,“pre”类型的过滤器是在(exchanges,chain)->{}中执行的,而“post”类型的过滤器是在chain.filter(exchange).then(Mono.fromRunnable(()->{}))中执行的。

 

6.2 Forward Routing Filter

 这个全局过滤器的实现类是:ForwardRoutingFilter,请求过来吧,它会从exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);获取路由配置的URI,如果这个URI是forward模式,过滤器会将请求转发到DispatcherHandler,然后匹配到网关本的请求路径之中,原来请求的URI将被forward的URI覆盖,原始的请求URI被存储到exchange的ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性之中。

例如下面的配置:

- id: forward_routing_filter
        uri: forward:///app
        order: 10000
        predicates:
        - Path=/forwardFilter
        filters:
        - PrefixPath=/gateway

在spring-cloud-gateway中添加跳转的FowardRoutingFilterController,来用接收跳转之后的请求:

@RestController
@RequestMapping("gateway")
public class FowardRoutingFilterController {
    @RequestMapping("app")
    public String  globalFilters() {
        return "Forward跳转成功";
    }
}

在浏览器中输入:http://localhost:8080/forwardFilter,在spring-cloud-gateway服务收到请求之后,会执行以下步骤:

  • 根据请求路径/forwardFilter匹配到路由forward_routing-filter,并将请求跳转为:http://localhost:8080/app
  • filters里面的PrefixPath配置请求改写为:http://localhost:8080/gateway/app
  • ForwardRoutingFilter过滤器中判断路由中有foroward://前缀,将请求转发给DispatcherHandler
  • DispatcherHandler匹配并转到spring-cloud-gateway服务中的contoller匹配的路径

为了方便看到路径的变化,我们可以定义一个全局的过滤器:MyGlobalFitlers ,如下面代码所示:

@Service
public class MyGlobalFitlers implements GlobalFilter, Ordered{

    private Logger logger = LoggerFactory.getLogger(MyGlobalFitlers.class);
    @Override
    public int getOrder() {
        return 10001;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        Object value = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        Object after = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
        logger.debug("global filters:{},{}",value,after);
        return chain.filter(exchange);
    }

}

在浏览器中输入:http://localhost:8080/forwardFilter,在控制台上日志可以看到前后不同的两个请求地址:

global filters:http://localhost:8080/gateway/app,[http://localhost:8080/app]

 

6.3 LoadBalancerClient Filter

这个全局过滤器的实现类是:LoadBalancerClientFilter,它是用来处理负载均衡的过滤器。在网关后面的服务可以启动多个服务实例,这个过滤器就是把请求根据均衡规则路由到某台服务实例上面。它从exchange的ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR属性中获取URI,如果这个URI的scheme是“lb”,如:lb://myserivce,它会使用spring cloud 的LoadBalancerClient解析myservice服务名,获取一个服务实例的host和port,并替换原来的客户端请求。原来请求的url会存储在exchange的ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性中。这个过滤器也会从exchange中获取ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR属性值,如果它的值也是“lb”,也会使用相同的规则路由。

如下面配置:

- id: balanceclient_route
        uri: lb://app-a
        predicates:
        - Path=/app-a/app/**

app-a是服务的名字,即spring.application.name的值 ,启动两个app-a的服务,在浏览器中输入http://localhost:8080/app-a/app/balance,点击多次,可以看到app-a的两个服务实例都有日志输入,说明每个实例都被请求到了,实现了负载均衡。

 注意:默认情况下,如果LoadBalancer根据配置的实例名找不到有效的服务实例,返回状态码503,如果你想配置返回404,可以这样设置:

spring.cloud.gateway.loadbalancer.use404=true

另外,Loadbalancer找到的服务实例ServiceInstance的方法isSecure的值,会覆盖请求中的scheme,比如如果请求网关的url的scheme是https,但是isSecure的值是false,在转发请求的时候,请求url的scheme会变成http,反过来也是一样的。但是,如果exchange的GATEWAY_SCHEME_PREFIX_ATTR属性在网关配置中被指定某个值,那么这个值将会覆盖ServiceInstance的配置。

6.4 Netty Routing Filter

这个全局过滤器的实现类是:NettyRoutingFilter,这是一个优先级最低的过滤器,如果从exchange的ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR获取的URL的scheme是https或http,它将使用Netty的HttpClient创建向下执行的请求代理,请求返回的结果将存储在exchange的ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR属性中,过滤器链后面的过滤器可以从中获取返回的结果。(还有一个测试使用的过滤器,WebClientHttpRoutingFilter,它和NettyRoutingFilter的功能一样,但是不使用netty)。

6.5 Netty Write Response Filter

这个全局过滤器的实现类是:NettyWriteResponseFilter,它的优先级是最高的,它是“post”类型的过滤器。如果在exchange中ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR的属性存在HttpClientResponse,它会在所有的其它的过滤器执行完成之后运行,将响应的数据发送给网关的客户端。

 

6.6 RouteToRequestUrl Filter

这个全局过滤器的实现类是:RouteToRequestUrlFilter,它的作用是把浏览器的URL请求的Path路径添加到路由的URI之中,比如浏览器请求网关的URL是:http://localhost:8080/app-a/app/balance,路由的URI配置是:uri: lb://app-a,那么添加之后的路由的URI是:lb://app-a/app/balance,并将它存储在exchange的ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR属性之中。

6.7 Websocket Routing Filter

这个全局过滤器的实现类是:WebsocketRoutingFilter,它是用来路由WebScoket请求,在exchange的ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR的URI中,如果scheme是ws或wss,它会使用Spring Web Socket 模块转发WebSocket请求。WebSockets可以使用路由进行负载均衡,比如:lb:ws://serviceid 

如果在客户端使用了SockJS,那么应该配置一个普通的Http路由。如下面配置所示:

spring:
  cloud:
    gateway:
      routes:
      # SockJS route
      - id: websocket_sockjs_route
        uri: http://localhost:3001
        predicates:
        - Path=/websocket/info/**
      # Normwal Websocket route
      - id: websocket_route
        uri: ws://localhost:3001
        predicates:
        - Path=/websocket/**

6.8 Gateway Metrics Filter

这个全局过滤器的实现类是:GatewayMetricsFilter,它用来统计一些网关的性能指标。需要添加spring-boot-starter-actuator的项目依赖,

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

 

默认情况下,只要spring.cloud.gateway.metrics.enabled设置不是false,这个过滤器就生效。这个过滤器会添加一个名字为“gateway.requests”和tags为如下的timer metric:

  • routeId: 路由的id
  • routeUri:被路由的URI
  • outcome:被HttpStatus.Series标记的结果
  • status : 返回给客户端的http状态码

这些指标可以通过/actuator/metrics/gateway.requests查看,但是需要开启权限,如下面application.yml配置:

management: 
  endpoints: 
    web: 
      exposure:  
        include: "*"

注意,如果网关一次都没有被请求过,这时请求/actuator/metrics/gateway.requests会返回404,网关必须被请求过一次,才会正常返回监控的一些指标。

而且网关的这些监控指标可以整合到Prometheus,创建一个Grafana dashboard。

Prometheus是一款监控工具,Grafana是一款监控可视化工具;Spring Boot Actuator可与这两款工具进行整合,需要添加micrometer-registry-prometheus依赖

        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>

 第二件1.9元】草原传奇 白蘑牛肉酱180g*2瓶香辣牛肉酱蘑菇酱拌饭酱拌面酱内蒙特产 草原传奇白蘑牛肉酱 2瓶

 

6.9 Making An Exchange As Routed

如果网关已经路由过一个ServerWebExchange,它将标记这个exchange已经被路由过,记录在exchange的ServerWebExchangeUtils.GATEWAY_ALREADY_ROUTED_ATTR属性中。一旦被标记完成了路由,其它的路由过滤器将不会再路由本次请求,直接跳过此过滤器。有两个方便的方法,你可以使用它们标记已路由过或检测是否已路由过

  • ServerWebExchangeUtils.isAlreadyRouted takes a ServerWebExchange object and checks if it has been "routed"
  • ServerWebExchangeUtils.setAlreadyRouted takes a ServerWebExchange object and marks it as "routed"

 

posted @ 2019-10-07 22:07  王广帅  阅读(7200)  评论(0编辑  收藏  举报