一、ERROR Filter
错误过滤器用来处理zuul异常,一般使作为打印异常堆栈、跳转异常页面、转换异常信息格式返回等操作。
Zuul已定义的错误过滤器SendErrorFilter
,如果RequestContext.getThrowable()
不为null,则转发到/error
(默认情况下)。您可以通过设置error.path
属性来更改默认转发路径(/error
)。
二、自定义错误过滤器
本文自定义错误过滤器用来将json格式请求的异常信息转换成json格式返回。
三、实现代码
@Component
@Slf4j
public class ErrorFilter extends ZuulFilter {
//按类型对过滤器进行分类。Zuul中的标准类型是"pre"用于预路由筛选,"route"用于路由到原点,"post"用于后路由筛选,"error"用于错误处理。
//我们还支持静态响应的"static"类型请参阅StaticResponseFilter。可以通过调用FilterProcessor.runFilters(type)
//前置过滤器必须返回error
@Override
public String filterType() {
return FilterConstants.ERROR_TYPE;
}
//必须为过滤器定义filterOrder。如果优先级对筛选器不重要,则过滤器可能具有相同的过滤器顺序
//过滤器顺序不需要是连续的
@Override
public int filterOrder() {
return FilterConstants.SEND_ERROR_FILTER_ORDER - 10;
}
//默认情况下,zuulfilter是静态的;它们不携带状态。这可以通过将isStaticFilter属性重写为false来重写
@Override
public boolean isStaticFilter() {
return super.isStaticFilter();
}
//要禁用此筛选器的Archaius属性的名称。默认情况下,它是zuul.[classname].[filtertype].disable
@Override
public String disablePropertyName() {
return super.disablePropertyName();
}
//如果为true,则过滤器已被archaius禁用,不会运行
@Override
public boolean isFilterDisabled() {
return super.isFilterDisabled();
}
//此方法返回的"true"表示应该调用run方法
//如果应该调用run方法,则返回true。false不会调用run方法
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
String contentType = ctx.getRequest().getContentType();
if (contentType == null) {
return true;
}
MediaType mediaType = MediaType.valueOf(contentType);
if(mediaType == null){
return true;
}
return MediaType.APPLICATION_JSON.includes(mediaType);
}
//如果shouldFilter方法为true,则将调用此方法。这种方法是ZuulFilter的核心方法
//返回一些可以返回的任意工件。当前的实现忽略了它。
//如果在执行期间发生错误,则引发ZuulException
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
ZuulException exception = findZuulException(context.getThrowable());
context.remove("throwable");//去掉已处理的错误信息
try {
HttpServletResponse response = context.getResponse();
response.setContentType("application/json; charset=utf8");
response.setStatus(exception.nStatusCode);
PrintWriter writer = null;
try {
writer = response.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("code", exception.nStatusCode);
map.put("msg", exception.errorCause);
map.put("detail", exception.getMessage());
String retStr = JSON.toJSONString(map);
writer.print(retStr);
writer.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null) {
writer.close();
}
}
}catch (Exception e){
log.error("error filter exception", e);
}
return null;
}
protected ZuulException findZuulException(Throwable throwable) {
if (throwable.getCause() instanceof ZuulRuntimeException) {
Throwable cause = null;
if (throwable.getCause().getCause() != null) {
cause = throwable.getCause().getCause().getCause();
}
if (cause instanceof ClientException && cause.getCause() != null
&& cause.getCause().getCause() instanceof SocketTimeoutException) {
ZuulException zuulException = new ZuulException("", 504,
ZuulException.class.getName() + ": Hystrix Readed time out");
return zuulException;
}
// this was a failure initiated by one of the local filters
if (throwable.getCause().getCause() instanceof ZuulException) {
return (ZuulException) throwable.getCause().getCause();
}
}
if (throwable.getCause() instanceof ZuulException) {
// wrapped zuul exception
return (ZuulException) throwable.getCause();
}
if (throwable instanceof ZuulException) {
// exception thrown by zuul lifecycle
return (ZuulException) throwable;
}
// fallback
return new ZuulException(throwable, HttpStatus.INTERNAL_SERVER_ERROR.value(), null);
}
}