SpringBoot - Filters exception handler

8k Views Asked by At

I have a spring-boot application. I have a class that is ControllerAdvice to handle the exceptions thrown by the app.

I created a filter that I want to use it to validate a header for all my requests. When I throw the custom exception from that filter, it does not go through my exception handler, it uses the default Spring error control.

Is there any way to handle the errors from filters in my own way?

2

There are 2 best solutions below

1
user7456343 On

You can write a controller that extends BasicErrorController and write a method that has a @GetMapping annotation like this:

@RestController
public class FilterExceptionController extends BasicErrorController {

    private static final Logger LOGGER = LoggerFactory.getLogger(FilterExceptionController.class);

    public FilterExceptionController(){
        super(new DefaultErrorAttributes(),new ErrorProperties());
    }

    @GetMapping
    private <T> ResponseResult<T> serviceExceptionHandler(HttpServletRequest request) {
        Map<String,Object> body= getErrorAttributes(request,isIncludeStackTrace(request,MediaType.ALL));
        String message = String.valueOf(body.get("message"));
        body.forEach((k,v)->LOGGER.info("{} ==> {}",k,v));
        return RestResultGenerator.genError(500,"Filter Error Occurred, Message: [ "+message+" ]");
    }

    @Override
    public String getErrorPath() {
        return "/error";
    }
}

There is my test filter:

@WebFilter(filterName = "ipFilter",urlPatterns = "/*")
public class IpFilter implements Filter{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if(!Arrays.asList(new String[]{"127.0.0.1"}).contains(servletRequest.getRemoteAddr())){
            throw new ServiceException(403,"ip forbid");
        }
    }

    @Override
    public void destroy() {

    }
}

This is result(but only get exception message not code): enter image description here

0
Tony Murphy On

If you catch the exception in a Filter, then handle with HandlerExceptionResolver, the @ControllerAdvice will start to work

import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class HystrixRequestContextServletFilter extends OncePerRequestFilter {

    private static final String API_KEY = "apiKey";

    private final HandlerExceptionResolver handlerExceptionResolver;

    @Autowired
    public HystrixRequestContextServletFilter(HandlerExceptionResolver handlerExceptionResolver) {
        this.handlerExceptionResolver = handlerExceptionResolver;
    }

    @Override
    public void doFilterInternal(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain filterChain) {
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        try {
            String apiKey = httpRequest.getHeader(API_KEY);
            if (apiKey == null) {
                throw new AuthenticationException("no apikey in request, path [" + httpRequest.getRequestURI() + "]");
            }
            ApiKeyHystrixRequestVariable.set(apiKey);
            filterChain.doFilter(httpRequest, httpResponse);
        } catch (Exception e) {
            handlerExceptionResolver.resolveException(httpRequest, httpResponse, null, e);
        } finally {
            context.shutdown();
        }
    }

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        return request.getRequestURI().startsWith("/internal");
    }

}