一、概述
Spring Cloud Gateway將路由作為Spring WebFlux HandlerMapping基礎結構的一部分進行匹配。 Spring Cloud Gateway包含許多內置的Route Predicate Factories。所有這些謂詞都匹配HTTP請求的不同屬性。多路線謂詞工廠可以組合,並通過邏輯and。
路由選擇是通過Predicate函數式接口進行判斷當前路由是否滿足給定條件。
附注:關於jdk8的Predicate Predicate<T> 接受一個輸入參數,返回一個布爾值結果。該接口包含多種默認方法來將Predicate組合成其他復雜的邏輯(比如:與,或,非)。可以用於接口請求參數校驗、判斷新老數據是否有變化需要進行更新操作。
add--與、or--或、negate--非 boolean test(T t); 判斷 Predicate<T> and(Predicate<? super T> other) 接收一個Predicate類型,也就是將傳入的條件和當前條件以並且(AND)的關系組合 Predicate<T> or(Predicate<? super T> other)接收一個Predicate類型,也就是將傳入的條件和當前條件以或(OR)的關系組合 更多參看:https://www.cnblogs.com/bjlhx/p/9711292.html
1.1、路由謂詞創建及使用
1️⃣、加載路由中的Predicate
/** * 返回組合的謂詞 * @param routeDefinition * @return */ private Predicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) { //獲取RouteDefinition中的PredicateDefinition集合 List<PredicateDefinition> predicates = routeDefinition.getPredicates(); Predicate<ServerWebExchange> predicate = lookup(routeDefinition, predicates.get(0)); for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) { Predicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate); //返回一個組合的謂詞,表示該謂詞與另一個謂詞的短路邏輯AND predicate = predicate.and(found); } return predicate; } /** * 獲取一個謂語定義(PredicateDefinition)轉換的謂語 * @param route * @param predicate * @return */ @SuppressWarnings("unchecked") private Predicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) { //獲取謂語創建工廠 RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName()); if (factory == null) { throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName()); } //獲取參數 Map<String, String> args = predicate.getArgs(); if (logger.isDebugEnabled()) { logger.debug("RouteDefinition " + route.getId() + " applying " + args + " to " + predicate.getName()); } //組裝參數 Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory); //構建創建謂語的配置信息 Object config = factory.newConfig(); ConfigurationUtils.bind(config, properties, factory.shortcutFieldPrefix(), predicate.getName(), validator); if (this.publisher != null) { this.publisher.publishEvent(new PredicateArgsEvent(this, route.getId(), properties)); } //通過謂語工廠構建謂語 return factory.apply(config); }
- 獲取路由定義(routeDefinition)所有的謂語定位(PredicateDefinition)
- 以此根據謂語定義(PredicateDefinition)查找謂語對於的創建工廠(RoutePredicateFactory) 創建謂語
- 通過 Predicate<T>接口 and方法合並謂語集合返回一個新的復合謂語
2️⃣、使用路由Predicate判斷路由是否可用
在Spring-Cloud-Gateway之請求處理流程里,在handlerMapping中通過路由定位器獲取所有路由,並過濾掉謂語判斷失敗的路由,最終獲取滿足條件的路由protected Mono<Route> lookupRoute(ServerWebExchange exchange) { //通過路由定位器獲取路由信息 return this.routeLocator.getRoutes() .filter(route -> { exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, route.getId()); //返回通過謂語過濾的路由信息 return route.getPredicate().test(exchange); }); }
通過上面兩步可以看到了整個路由的條件創建以及使用的地方以及流程,Spring-Cloud-Gateway通過Predicate接口完成簡單條件組合以及判斷。
1.2、RoutePredicateFactory 路由謂詞工廠

按照子類功能划分:
1️⃣、MethodRoutePredicateFactory
/** * 請求方式(GET,POST,DEL,PUT)校驗匹配創建工廠 */ public class MethodRoutePredicateFactory extends AbstractRoutePredicateFactory<MethodRoutePredicateFactory.Config> { public static final String METHOD_KEY = "method"; @Override public Predicate<ServerWebExchange> apply(Config config) { return exchange -> { //獲取當前請求的HttpMethod HttpMethod requestMethod = exchange.getRequest().getMethod(); //校驗請求HttpMethod與配置是否一致 return requestMethod == config.getMethod(); }; } public static class Config { /** * http 請求Method */ private HttpMethod method; public HttpMethod getMethod() { return method; } public void setMethod(HttpMethod method) { this.method = method; } } }
配置示例
spring: cloud: gateway: routes: # ===================================== - id: method_route uri: http://example.org predicates: - Method=GET
過程:
- Method=GET 會被解析成PredicateDefinition對象 (name =Method ,args= GET)
- 通過PredicateDefinition的Name找到MethodRoutePredicateFactory工廠
- 通過 PredicateDefinition 的args 創建Config對象(HttpMethod=GET)
- 通過 MethodRoutePredicateFactory工廠的apply方法傳入config創建Predicate對象。
1.3、全部謂詞配置
1.3.1、After Route Predicate Factory
此謂詞匹配當前日期時間之后發生的請求。
application.yml
spring:
cloud:
gateway:
routes:
- id: after_route uri: http://example.org predicates: - After=2017-01-20T17:42:47.789-07:00[America/Denver]
1.3.2、Before Route Predicate Factory
此謂詞匹配在當前日期時間之前發生的請求。
application.yml
spring:
cloud:
gateway:
routes:
- id: before_route uri: http://example.org predicates: - Before=2017-01-20T17:42:47.789-07:00[America/Denver]
1.3.3、Between Route Predicate Factory
此謂詞匹配datetime1之后和datetime2之前發生的請求。 datetime2參數必須在datetime1之后。
application.yml
spring:
cloud:
gateway:
routes:
- id: between_route uri: http://example.org predicates: - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
1.3.4、Cookie Route Predicate Factory
Cookie Route Predicate Factory有兩個參數,cookie名稱和正則表達式。此謂詞匹配具有給定名稱且值與正則表達式匹配的cookie。
application.yml
spring:
cloud:
gateway:
routes:
- id: cookie_route uri: http://example.org predicates: - Cookie=chocolate, ch.p
此路由匹配請求有一個名為chocolate的cookie,其值與ch.p正則表達式匹配。
1.3.5、Header Route Predicate Factory
Header Route Predicate Factory有兩個參數,標題名稱和正則表達式。此謂詞與具有給定名稱且值與正則表達式匹配的標頭匹配。
application.yml
spring:
cloud:
gateway:
routes:
- id: header_route uri: http://example.org predicates: - Header=X-Request-Id, \d+
如果請求具有名為X-Request-Id的標頭,則該路由匹配,其值與\ d +正則表達式匹配(具有一個或多個數字的值)。
1.3.6、Host Route Predicate Factory
Host Route Predicate Factory采用一個參數:主機名模式。該模式是一種Ant樣式模式“.”作為分隔符。此謂詞匹配與模式匹配的Host標頭。
application.yml
spring:
cloud:
gateway:
routes:
- id: host_route uri: http://example.org predicates: - Host=**.somehost.org
如果請求的主機頭具有值www.somehost.org或beta.somehost.org,則此路由將匹配。
1.3.7、Method Route Predicate Factory
Method Route Predicate Factory采用一個參數:要匹配的HTTP方法。
spring:
cloud:
gateway:
routes:
- id: method_route uri: http://example.org predicates: - Method=GET
1.3.8、Path Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: host_route uri: http://example.org predicates: - Path=/foo/{segment}
/foo/1
or /foo/bar
.
1.3.9、Query Route Predicate Factory
Query Route Predicate Factory有兩個參數:一個必需的參數和一個可選的正則表達式。
spring:
cloud:
gateway:
routes:
- id: query_route uri: http://example.org predicates: - Query=baz
如果請求包含baz查詢參數,則此路由將匹配。
spring:
cloud:
gateway:
routes:
- id: query_route uri: http://example.org predicates: - Query=foo, ba.
如果請求包含其值與ba匹配的foo查詢參數,則此路由將匹配。 regexp,所以bar和baz匹配。
1.3.10、RemoteAddr Route Predicate Factory
RemoteAddr Route Predicate Factory采用CIDR符號(IPv4或IPv6)字符串的列表(最小值為1),例如, 192.168.0.1/16(其中192.168.0.1是IP地址,16是子網掩碼)。
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route uri: http://example.org predicates: - RemoteAddr=192.168.1.1/24
如果請求的遠程地址是例如192.168.1.10,則此路由將匹配。