https://www.codenong.com/jsf04a503f0d32/
spring cloud gateway 二次開發之 動態路由注意事項
網關開發的過程中,因為有對某些服務進行動態的上下線的需求,所以進行了動態路由的開發,網上也有例子,實現方式就不贅述了,但這里有2個注意事項。
一 路由信息里的斷言器信息不能為空
如果沒有傳斷言器信息,比如這樣
1
2 3 4 5 6 7 |
{
"id":"test", "predicates":[], "filters":[], "uri":"lb://test", "order":0 } |
會拋出異常
1
2 3 4 5 6 |
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at java.util.ArrayList.rangeCheck(ArrayList.java:653) at java.util.ArrayList.get(ArrayList.java:429) at org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator.combinePredicates(RouteDefinitionRouteLocator.java:221) at org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator.convertToRoute(RouteDefinitionRouteLocator.java:143) |
我們看路由信息類的時候,可以發現斷言器是一個List,RouteDefinitionRouteLocator下邊有這個方法,會先取List中第一個斷言器,然后與之后的斷言器做組合,
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
private AsyncPredicate<ServerWebExchange> combinePredicates(
RouteDefinition routeDefinition) { List<PredicateDefinition> predicates = routeDefinition.getPredicates(); //取出第一個斷言器 AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition, predicates.get(0)); //取出后續斷言器 for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) { AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate); //第一個斷言器和后續斷言器做 and 操作 predicate = predicate.and(found); } return predicate; } |
如果沒有填斷言器信息,就會報數組越界異常
二 斷言器的名字不能隨便取
比如這里我取了一個 zuibuxing 的斷言器名字
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{
"id":"test", "predicates":[ { "name":"zuibuxing", "args":{ "_genkey_0":"/test/**" } } ], "filters":[ ], "uri":"lb://test", "order":0 } |
會報這個錯誤
1
2 3 4 5 |
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalArgumentException: Unable to find RoutePredicateFactory with name zuibuxing
Caused by: java.lang.IllegalArgumentException: Unable to find RoutePredicateFactory with name zuibuxing at org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator.lookup(RouteDefinitionRouteLocator.java:240) at org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator.combinePredicates(RouteDefinitionRouteLocator.java:220) at org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator.convertToRoute(RouteDefinitionRouteLocator.java:143) |
說找不到名字為 zuibuxing 的斷言器,這是因為保存自定義路由的時候,RouteDefinitionRouteLocato 會按照 name 去斷言器Map 里去尋找,
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
... 中間代碼省略 .... //按照名字尋找斷言器 private AsyncPredicate<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()); } ...以下代碼省略 } |
1
|
|
RouteDefinitionRouteLocator 在這個Map中保存所有實現了 RoutePredicateFactory 的類,name是類名去掉RoutePredicateFactory,比如 AfterRoutePredicateFactory 斷言器的名字是 After,這里有兩個特殊的斷言器 CloudFoundryRouteService,ReadBodyPredicateFactory,因為它們的類名沒有以 RoutePredicateFactory 結尾,所以就用本身類名作為 斷言器name
如果是隨便寫的,會導致找不到斷言器報錯,所以我們只能填gateway自己的斷言器,或者自己實現了 RoutePredicateFactory 的斷言器