详解SpringCloud Finchley Gateway 统一异常处理
这篇文章主要介绍了详解SpringCloud Finchley 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 .参考此方法思路,可实现统一异常处理,统一封装错误信息。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持CodeAE代码之家。
原文链接:https://segmentfault.com/a/1190000016854364
http://www.zzvips.com/article/169721.html
页:
[1]