Spring Cloud zuul custom unified exception handling implementation method
- 2021-01-22 05:11:28
- OfStack
Zuul provides filer and router functions in the springcloud microservice architecture, which is an integral part of the microservice. filer handles the default implementation but also can be customized for authorization, current limitation, security verification, etc. router can completely replace Nginx reverse proxy. Zuul exception handling is done by SendErrorFilter.
In our application we found that using the default exception filter has two problems that are not very friendly:
1. Unable to quickly identify whether the request routing service timeout or no available nodes, error can only view the log through the stack to locate;
2. Not compatible with custom examples
{code:500,msg:”xx error”}
Format response package format.
Next we discuss how to customize exception handling, custom exception prompts, and so on.
First of all, we must disable the default SendErrorFilter. The official switch configuration is provided and can be configured directly
zuul.SendErrorFilter.post.disable=true
Custom ErrorFilter, here is not much to say, directly posted code
public class ErrorFilter extends ZuulFilter {
private static final String ERROR_STATUS_CODE_KEY = "error.status_code";
private Logger log = LoggerFactory.getLogger(ErrorFilter.class);
public static final String DEFAULT_ERR_MSG = " System is busy , Please try again later ";
@Override
public String filterType() {
return "post";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return ctx.containsKey(ERROR_STATUS_CODE_KEY);
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
try {
HttpServletRequest request = ctx.getRequest();
int statusCode = (Integer) ctx.get(ERROR_STATUS_CODE_KEY);
String message = (String) ctx.get("error.message");
if (ctx.containsKey("error.exception")) {
Throwable e = (Exception) ctx.get("error.exception");
Throwable re = getOriginException(e);
if(re instanceof java.net.ConnectException){
message = "Real Service Connection refused";
log.warn("uri:{},error:{}" ,request.getRequestURI(),re.getMessage());
}else if(re instanceof java.net.SocketTimeoutException){
message = "Real Service Timeout";
log.warn("uri:{},error:{}" ,request.getRequestURI(),re.getMessage());
}else if(re instanceof com.netflix.client.ClientException){
message = re.getMessage();
log.warn("uri:{},error:{}" ,request.getRequestURI(),re.getMessage());
}else{
log.warn("Error during filtering",e);
}
}
if(StringUtils.isBlank(message))message = DEFAULT_ERR_MSG;
request.setAttribute("javax.servlet.error.status_code", statusCode);
request.setAttribute("javax.servlet.error.message", message);
WebUtils.responseOutJson(ctx.getResponse(), JsonUtils.toJson(new WrapperResponse<>(statusCode, message)));
} catch (Exception e) {
String error = "Error during filtering[ErrorFilter]";
log.error(error,e);
WebUtils.responseOutJson(ctx.getResponse(), JsonUtils.toJson(new WrapperResponse<>(500, error)));
}
return null;
}
private Throwable getOriginException(Throwable e){
e = e.getCause();
while(e.getCause() != null){
e = e.getCause();
}
return e;
}
}
Finally, register for our custom ErrorFilter
@Bean
public ErrorFilter errorFilter(){
return new ErrorFilter();
}
conclusion