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"

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM