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 的断言器