threeperson
发布于 2019-12-07 / 1 阅读
0
0

springcloud 网关异常拦截

最近线上上午8:30左右,gateway会cpu告警,因为我们的服务可以自动伸缩,访问服务也正常,没有太在意这个问题。

上班路上突然收到项目经理和客户线上问题反馈记录。部分三方分享链接打开显示如下内容。

```

{"code":1021,"msg":"网关内部异常.","timestamp":"1575616043978","result":null,"success":false}

```

第一反应,再次打开app分享一个链接到微信,打开没问题。初步判断是网关告警时出了问题。

到公司赶紧排查了一下日志,发现扩容节点存在部分请求失败,异常信息如下。

```

FilterProcessor.java:193)\n\t... 72 common frames omitted\nCaused by: com.netflix.client.ClientException: Load balancer does not have available server for client: USER-CENTER\n\tat com.netflix.loadbalancer.LoadBalancerContext.getServerFromLoadBalancer(LoadBalancerContext.java:483)\n\tat com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:184)\n\tat com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180)\n\tat rx.Observable.unsafeSubscribe(Observable.java:10327)\n\tat rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94)\n\tat rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42)\n\tat rx.Observable.unsafeSubscribe(Observable.java:10327)\n\tat rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:127)\n\tat rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73)\n\tat rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52)\n\tat rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:79)\n\tat rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45)\n\tat rx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276)\n\tat rx.Subscriber.setProducer(Subscriber.java:209)\n\tat rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138)\n\tat rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129)\n\tat rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)\n\tat rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)\n\tat rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)\n\tat rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)\n\tat rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)\n\tat rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)\n\tat rx.Observable.subscribe(Observable.java:10423)\n\tat rx.Observable.subscribe(Observable.java:10390)\n\tat rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:443)\n\tat rx.observables.BlockingObservable.single(BlockingObservable.java:340)\n\tat com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:112)\n\tat org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:63)\n\t... 88 common frames

```

由于网关ErrorFilter中我把所有的异常都处理成了json返回,导致访问html时也返回了json字符串。至于为什么扩容服务出现了服务不可用,后面会详细讨论。

下面写一下处理办法。

###在gatewany中整合thymeleaf

* pom.xml 追加依赖

```

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-thymeleaf</artifactId>

</dependency>

```

* 添加静态资源路径

```

mvc:

throw-exception-if-no-handler-found: true

static-path-pattern: /static/**

resources:

add-mappings: false

```

* 通过configuration 配置一下路径(我们用的2.0.4,发现仅配置文件不好使)

```

@Configuration

public class MvcConfiguration implements WebMvcConfigurer {

@Override

public void addResourceHandlers(ResourceHandlerRegistry registry) {

registry

.addResourceHandler("/static/**")

.addResourceLocations("classpath:/static/");

}

}

```

* 添加一个ErrorController 用来跳转异常页(因为resources 下资源不可以直接访问)

```

@Controller

public class ErrorController {

@RequestMapping("404.html")

public String go404(){

return "error/404";

}

@RequestMapping("500.html")

public String go500(){

return "error/500";

}

}

* 过滤器中针对html访问失败,跳转500页面

```

if(isStaticResourceRequest(uri) && !response.isCommitted()){

response.sendRedirect("/500.html")

return null;

}

boolean isStaticResourceRequest(String url){

String reg = ".+(.html)\$"

Pattern pattern = Pattern.compile(reg)

Matcher matcher = pattern.matcher(url)

return matcher.find()

}

```

配置这些就ok了,如果微服务不可用,且访问的是html页面,那么就会跳转到一个异常页;如果访问不是页面,依然还是json格式的错误内容。


评论