上一篇文章《微服务实战spring cloud alibaba(十六)实现在nacos上配置动态路由》我们在spring cloud gateway里面配置了动态路由,最后测试是成功的。但是我们转念一想,万一如果某人请求到我们的某个url在gateway里面找不到路由,无法实现转发怎么办呢?这里我们测试下,请求地址:http://127.0.0.1:9010/goods1/good/info/1,可以了解到我们没有配置goods1这个路由转发,因此肯定是找不到的,结果如图:
我们会发现一个问题,就是我们所有后端服务的接口统一返回的格式是这样的:
{ "data": {}, "errorCode": 200, "errorMsg": "请求成功" }
但是在这里返回的404的格式缺不是标准的返回,而是返回了
{ "timestamp": "2023-02-28T07:12:24.088+00:00", "path": "/goods1/good/info/1", "status": 404, "error": "Not Found", "message": null, "requestId": "79bcbe48-1" }
那这样子怎么办呢? 难道要让前端写两套解析代码? 这肯定是不现实的,我们有没有办法把spring cloud gateway这里返回的404改成写我们的标配json内容呢? 答案是肯定的。
在spring cloud gateway里面如果需要修改这里的话,我们可以找到这个类的源码:org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler。这个怎么着呢,其实在我们的编辑器里面随便找个地方把这个类引用进来
然后我们点击这个类点击进去,我们就可以看到源码了
然后我们把这个源码拷贝进来,然后在spring cloud gateway项目里面创建一个一模一样的报名,把这个类放进去。
然后我们打开这个类,进去找到这个方法
public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) {
我们要做的就是修改这个方法,处理成我们自己自定义的,这里的话,我们主要是处理404的code码,所以我们在这后面修改自己的逻辑接口。
@Override public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) { if (exchange.getResponse().isCommitted() || isDisconnectedClientError(throwable)) { return Mono.error(throwable); } this.errorAttributes.storeErrorInformation(throwable, exchange); ServerRequest request = ServerRequest.create(exchange, this.messageReaders); //TODO 在这里写自己的处理方法 //TODO 在这里写自己的处理方法 //TODO 在这里写自己的处理方法 //TODO 在这里写自己的处理方法 return getRoutingFunction(this.errorAttributes).route(request).switchIfEmpty(Mono.error(throwable)) .flatMap((handler) -> handler.handle(request)) .doOnNext((response) -> logError(request, response, throwable)) .flatMap((response) -> write(exchange, response)); }
我们处理的404的代码如下:
@Override public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) { if (exchange.getResponse().isCommitted() || isDisconnectedClientError(throwable)) { return Mono.error(throwable); } this.errorAttributes.storeErrorInformation(throwable, exchange); ServerRequest request = ServerRequest.create(exchange, this.messageReaders); if (throwable instanceof ResponseStatusException) { HttpStatus status = ((ResponseStatusException) throwable).getStatus(); if (HttpStatus.NOT_FOUND.equals(status)) { BaseResponsePoJo responsePoJo = BaseResponsePoJo.builder().errorCode(404).errorMsg("无有效的资源").build(); byte[] bytes = JSON.toJSONString(responsePoJo).getBytes(Charset.forName("utf-8")); ServerHttpResponse response = exchange.getResponse(); DataBuffer buffer = response.bufferFactory().wrap(bytes); response.setStatusCode(HttpStatus.OK); return response.writeWith(Mono.just(buffer)); } } return getRoutingFunction(this.errorAttributes).route(request).switchIfEmpty(Mono.error(throwable)) .flatMap((handler) -> handler.handle(request)) .doOnNext((response) -> logError(request, response, throwable)) .flatMap((response) -> write(exchange, response)); }
此时我们再启动spring cloud gateway项目,访问:http://127.0.0.1:9010/goods1/good/info/1,结果如下:
此时我们的responsejson就变成统一的格式了,非常方便。
备注:
1、这里我们采用的方式是修改源码的方式。
2、这里的AbstractErrorWebExceptionHandler这个类不是统一的,每个项目自己依赖的哪个版本就直接去找源码就可以了,不要直接用我这个,因为不同的版本对应的AbstractErrorWebExceptionHandler内容也不一样,运行起来可能会报错。
3、这里的404返回其实拦截的是spring cloud gateway,大家可能会首先想到使用filter进行拦截,特别提示下,filter拦截不到这里的404,filter只能拦截通过路由转发的下游服务的返回信息。
最后按照惯例,附上本案例的源码,登录后即可下载。
还没有评论,来说两句吧...