详解SpringCloud Finchley Gateway 统一异常处理
程序员文章站
2024-02-28 19:47:16
springcloud finchley gateway 统一异常处理
全文搜索[@@]搜索重点内容标记
1 . 问题:使用springcloud gateway时,会...
springcloud finchley gateway 统一异常处理
全文搜索[@@]搜索重点内容标记
1 . 问题:使用springcloud gateway时,会出现各种系统级异常,默认返回html.
2 . finchley版本的gateway,使用webflux形式作为底层框架,而不是servlet容器,所以常规的异常处理无法使用
翻阅源码,默认是使用defaulterrorwebexceptionhandler
这个类实现结构如下:
可以实现参考defaulterrorwebexceptionhandler
和abstracterrorwebexceptionhandler
自定义实现errorwebexceptionhandler
,然后,注册为bean到spring容器中即可(bean name:"errorwebexceptionhandler"
)
具体实现代码如下:
package pro.chenggang.example.spring.cloud.gateway.support; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.boot.web.reactive.error.errorwebexceptionhandler; import org.springframework.cloud.gateway.support.notfoundexception; import org.springframework.http.httpstatus; import org.springframework.http.mediatype; import org.springframework.http.codec.httpmessagereader; import org.springframework.http.codec.httpmessagewriter; import org.springframework.http.server.reactive.serverhttprequest; import org.springframework.util.assert; import org.springframework.web.reactive.function.bodyinserters; import org.springframework.web.reactive.function.server.requestpredicates; import org.springframework.web.reactive.function.server.routerfunctions; import org.springframework.web.reactive.function.server.serverrequest; import org.springframework.web.reactive.function.server.serverresponse; import org.springframework.web.reactive.result.view.viewresolver; import org.springframework.web.server.responsestatusexception; import org.springframework.web.server.serverwebexchange; import reactor.core.publisher.mono; import java.util.collections; import java.util.hashmap; import java.util.list; import java.util.map; /** * @classdesc: 统一异常处理,参考{@link org.springframework.web.server.abstracterrorwebexceptionhandler}修改 * @author: chenggang * @createtime: 2018/10/30 */ public class jsonexceptionhandler implements errorwebexceptionhandler { private static final logger log = loggerfactory.getlogger(jsonexceptionhandler.class); /** * messagereader */ private list<httpmessagereader<?>> messagereaders = collections.emptylist(); /** * messagewriter */ private list<httpmessagewriter<?>> messagewriters = collections.emptylist(); /** * viewresolvers */ private list<viewresolver> viewresolvers = collections.emptylist(); /** * 存储处理异常后的信息 */ private threadlocal<map<string,object>> exceptionhandlerresult = new threadlocal<>(); /** * 参考abstracterrorwebexceptionhandler * @param messagereaders */ public void setmessagereaders(list<httpmessagereader<?>> messagereaders) { assert.notnull(messagereaders, "'messagereaders' must not be null"); this.messagereaders = messagereaders; } /** * 参考abstracterrorwebexceptionhandler * @param viewresolvers */ public void setviewresolvers(list<viewresolver> viewresolvers) { this.viewresolvers = viewresolvers; } /** * 参考abstracterrorwebexceptionhandler * @param messagewriters */ public void setmessagewriters(list<httpmessagewriter<?>> messagewriters) { assert.notnull(messagewriters, "'messagewriters' must not be null"); this.messagewriters = messagewriters; } @override public mono<void> handle(serverwebexchange exchange, throwable ex) { /** * 按照异常类型进行处理 */ httpstatus httpstatus; string body; if (ex instanceof notfoundexception) { httpstatus = httpstatus.not_found; body = "service not found"; }else if(ex instanceof responsestatusexception) { responsestatusexception responsestatusexception = (responsestatusexception) ex; httpstatus = responsestatusexception.getstatus(); body = responsestatusexception.getmessage(); }else{ httpstatus = httpstatus.internal_server_error; body ="internal server error"; } /** * 封装响应体,此body可修改为自己的jsonbody */ map<string,object> result = new hashmap<>(2,1); result.put("httpstatus",httpstatus); result.put("body",body); /** * 错误记录 */ serverhttprequest request = exchange.getrequest(); log.error("[全局异常处理]异常请求路径:{},记录异常信息:{}",request.getpath(),ex.getmessage()); /** * 参考abstracterrorwebexceptionhandler */ if (exchange.getresponse().iscommitted()) { return mono.error(ex); } exceptionhandlerresult.set(result); serverrequest newrequest = serverrequest.create(exchange, this.messagereaders); return routerfunctions.route(requestpredicates.all(), this::rendererrorresponse).route(newrequest) .switchifempty(mono.error(ex)) .flatmap((handler) -> handler.handle(newrequest)) .flatmap((response) -> write(exchange, response)); } /** * 参考defaulterrorwebexceptionhandler * @param request * @return */ protected mono<serverresponse> rendererrorresponse(serverrequest request) { map<string,object> result = exceptionhandlerresult.get(); return serverresponse.status((httpstatus) result.get("httpstatus")) .contenttype(mediatype.application_json_utf8) .body(bodyinserters.fromobject(result.get("body"))); } /** * 参考abstracterrorwebexceptionhandler * @param exchange * @param response * @return */ private mono<? extends void> write(serverwebexchange exchange, serverresponse response) { exchange.getresponse().getheaders() .setcontenttype(response.headers().getcontenttype()); return response.writeto(exchange, new responsecontext()); } /** * 参考abstracterrorwebexceptionhandler */ private class responsecontext implements serverresponse.context { @override public list<httpmessagewriter<?>> messagewriters() { return jsonexceptionhandler.this.messagewriters; } @override public list<viewresolver> viewresolvers() { return jsonexceptionhandler.this.viewresolvers; } } }
注册bean
/** * 自定义异常处理[@@]注册bean时依赖的bean,会从容器中直接获取,所以直接注入即可 * @param viewresolversprovider * @param servercodecconfigurer * @return */ @primary @bean @order(ordered.highest_precedence) public errorwebexceptionhandler errorwebexceptionhandler(objectprovider<list<viewresolver>> viewresolversprovider, servercodecconfigurer servercodecconfigurer) { jsonexceptionhandler jsonexceptionhandler = new jsonexceptionhandler(); jsonexceptionhandler.setviewresolvers(viewresolversprovider.getifavailable(collections::emptylist)); jsonexceptionhandler.setmessagewriters(servercodecconfigurer.getwriters()); jsonexceptionhandler.setmessagereaders(servercodecconfigurer.getreaders()); log.debug("init json exception handler instead default errorwebexceptionhandler success"); return jsonexceptionhandler; }
[@@]注意事项:
1 .上面为示例代码,其中牵扯到策略工厂和响应封装的类,可以自定义实现
2 .注册bean时依赖的bean,都会从spring容器中获取到
3 .参考此方法思路,可实现统一异常处理,统一封装错误信息。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。