手记

自定义 ZuulFilter抛出异常

前提:
项目中统一使用 HttpResponseCode 来作为服务正常的返回, body 中放具体返回的内容.
如果抛出异常的情况下,期望 code 是4XX,body 中存放错误信息给用户友好提示
但是,在SpringCloud 中默认的异常抛出是一个包含五个字段的对象.如下:

{    "timestamp": 1513303905953,    "status": 400,    "error": "Bad Request",    "exception": "org.springframework.web.bind.MissingServletRequestParameterException",    "message": "Required Integer parameter 'userId' is not present",    "path": "/info"}

我们需要的是这样一种情况的:

Screen Shot 2017-12-15 at 2.23.05 PM.png

接下来我们来实现这种情况.


首先,第一个想到的是使用 @ControllerAdvice 来做全局的异常拦截,对异常进行处理

Screen Shot 2017-12-15 at 2.45.26 PM.png

但是,重启过后并没有什么作用,忽然想到@ControllerAdvice 应该是只处理到达 Controller 中的请求才能被拦截到,而 filter 在 controller 之前,所以拦截不到.那么就要找其他方法来处理.

ZuulFilter 中的 FilterType 中有一个 Error 的处理器.查找这方面资料StackOverflow,别人也遇到过这种情况需要同样的处理.
解决方案如下:

  1. error 类型的 zuulFilter

  2. 执行顺序在默认的 SendErrorFilter (index=0)之前,因此,我们设置为-1

  3. should 方法中检查有没有抛出异常

  4. run 方法中对异常进行处理

代码如下:

@Componentpublic class ErrorFilter extends ZuulFilter {    private final Logger log = LoggerFactory.getLogger(Http401UnauthorizedEntryPoint.class);    @Override
    public String filterType() {        return "error";
    }    @Override
    public int filterOrder() {        //需要在默认的 SendErrorFilter 之前
        return -1; // Needs to run before SendErrorFilter which has filterOrder == 0
    }    @Override
    public boolean shouldFilter() {        // only forward to errorPath if it hasn't been forwarded to already
        return RequestContext.getCurrentContext().containsKey("throwable");
    }    @Override
    public Object run() {        try {
            RequestContext ctx = RequestContext.getCurrentContext();
            Object e = ctx.get("throwable");            if (e != null && e instanceof ZuulException) {
                ZuulException zuulException = (ZuulException) e;                // Remove error code to prevent further error handling in follow up filters
                // 删除该异常信息,不然在下一个过滤器中还会被执行处理
                ctx.remove("throwable");                // 根据具体的业务逻辑来处理
                ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
                 
            }
        } catch (Exception ex) {
            log.error("Exception filtering in custom error filter", ex);
            ReflectionUtils.rethrowRuntimeException(ex);
        }        return null;
    }
}

注意:可能是因为版本不同, 上文链接解决方案中shoutFilter 中异常信息不一致,导致不能进入处理



作者:罗曼蒂克
链接:https://www.jianshu.com/p/2de6290d7bf1


0人推荐
随时随地看视频
慕课网APP