记一次网关异常
- 网关时不时就会出现下面的异常。关键是不知道什么时候就会报错,并且有时候就算什么都不操作,也会导致这个异常。
ERROR org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0at java.util.ArrayList.rangeCheck(ArrayList.java:657)at java.util.ArrayList.get(ArrayList.java:433)at org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator.combinePredicates(RouteDefinitionRouteLocator.java:238)at org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator.convertToRoute(RouteDefinitionRouteLocator.java:162)at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:100)at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:693)at reactor.core.publisher.FluxFlatMap$FlatMapMain.tryEmit(FluxFlatMap.java:553)at reactor.core.publisher.FluxFlatMap$FlatMapInner.onNext(FluxFlatMap.java:972)at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114)at reactor.core.publisher.FluxSubscribeOnValue$ScheduledScalar.run(FluxSubscribeOnValue.java:178)at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68)at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28)
· at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
- 经过搜索,说是gateway低代码版本的漏洞,然后解决方案是,使用nginx拦截actuator方法。
location /actuator {return 404;
}
虽然看着很简单,但是不了解实际原因,真的不敢随便这种升级,因为不确定这个方案到底有没有解决问题。一旦这种升级没有用,生产环境在产生同样的异常,就会给用户造成非常不要的影响,并且会让用户觉得我们不可信,所以还是要探求真正的原因。
- 之后,便从github的gateway官网上,找到了这个issue,看下面的讨论,发现是缺少Predicted的路由导致的。当路断言未空的时候,实际上是无法进行路由创建的,如果没有为空的判断,就会导致整个路由表崩溃,从而所有请求都报 500。下面是修正后的代码,就是当断言为空的时候,直接放行就行了。
-
然后,结合动态路由增删的这篇文章,我进行了本地代码的复现
-
首先定义动态增删路由的接口,见上面的文章。
-
其次发送post请求,增加一个接口,但是路由的断言不进行创建。也就是发送下面错误的请求体
post:localhost:8080/actuator/gateway/routes/demo2// 错误的请求体,但是实际上,接受参数的时候,是没有进行验证的。 { "id": "demo2", "uri": "http://fuzekun.top3/" } // 完整的请求体 { "id": "demo3", "uri": "http://fuzekun.top3/", "predicates": [ { "name": "Path", "args": { "pattern": "/blog3/**" } } ] }
-
最后发送refresh路由表的请求
post: localhost:8080/actuator/gateway/refresh
,就会得到上面的错误。
-
-
最后,通过升级springcloud gateway的版本,在重复上面的操作,可以发现,路由表仍旧是可以工作的。
最后最后,附上版本的对应表,项目报错使用的版本为
- spring cloud dependencies :Hoxton.SR2
- spring cloud alibaba : 2.2.0.RELEASE
修改后的版本为:
- Spring Cloud Dependencies :Hoxton.SR9
- spring cloud alibaba : 2.2.6.RELEASE