Spring中如何管理过滤器中抛出的异常?

新手上路,请多包涵

我想使用通用方式来管理 5xx 错误代码,让我们具体说一下当整个 spring 应用程序中的数据库关闭时的情况。我想要一个漂亮的错误 json 而不是堆栈跟踪。

对于控制器,我有一个 @ControllerAdvice 类用于不同的异常,这也捕获了数据库在请求中间停止的情况。但这并不是全部。 I also happen to have a custom CorsFilter extending OncePerRequestFilter and there when i call doFilter i get the CannotGetJdbcConnectionException and it will not be managed由 @ControllerAdvice 。我在网上阅读了几件事,这让我更加困惑。

所以我有很多问题:

  • 我需要实现自定义过滤器吗?我找到了 ExceptionTranslationFilter 但这只处理 AuthenticationExceptionAccessDeniedException
  • 我想实现自己的 HandlerExceptionResolver ,但这让我怀疑,我没有任何自定义异常需要管理,必须有比这更明显的方法。我还尝试添加一个 try/catch 并调用 HandlerExceptionResolver 的实现(应该足够好,我的例外没什么特别的)但这没有在响应中返回任何内容,我得到一个状态 200 和一个空的身体。

有什么好的方法可以解决这个问题吗?谢谢

原文由 kopelitsa 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 945
2 个回答

所以这就是我所做的:

我在 这里 阅读了有关过滤器的基础知识,发现我需要创建一个自定义过滤器,该过滤器将位于过滤器链中的第一个,并且将有一个 try catch 来捕获可能在那里发生的所有运行时异常。然后我需要手动创建 json 并将其放入响应中。

所以这是我的自定义过滤器:

 public class ExceptionHandlerFilter extends OncePerRequestFilter {

    @Override
    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            filterChain.doFilter(request, response);
        } catch (RuntimeException e) {

            // custom error response class used across my project
            ErrorResponse errorResponse = new ErrorResponse(e);

            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            response.getWriter().write(convertObjectToJson(errorResponse));
    }
}

    public String convertObjectToJson(Object object) throws JsonProcessingException {
        if (object == null) {
            return null;
        }
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(object);
    }
}

然后我将它添加到 CorsFilter 之前的 web.xml 中。它有效!

 <filter>
    <filter-name>exceptionHandlerFilter</filter-name>
    <filter-class>xx.xxxxxx.xxxxx.api.controllers.filters.ExceptionHandlerFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>exceptionHandlerFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

原文由 kopelitsa 发布,翻译遵循 CC BY-SA 3.0 许可协议

我想根据 @kopelitsa 的回答 提供一个解决方案。主要区别在于:

  1. 通过使用 HandlerExceptionResolver 重用控制器异常处理。
  2. 在 XML 配置上使用 Java 配置

首先,您需要确保您有一个类可以处理常规 RestController/Controller 中发生的异常(一个类注释为 @RestControllerAdvice@ControllerAdvice 和方法注释为 @ExceptionHandler )。这会处理控制器中发生的异常。下面是一个使用 RestControllerAdvice 的例子:

 @RestControllerAdvice
public class ExceptionTranslator {

    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorDTO processRuntimeException(RuntimeException e) {
        return createErrorDTO(HttpStatus.INTERNAL_SERVER_ERROR, "An internal server error occurred.", e);
    }

    private ErrorDTO createErrorDTO(HttpStatus status, String message, Exception e) {
        (...)
    }
}

要在 Spring Security 过滤器链中重用此行为,您需要定义一个过滤器并将其挂接到您的安全配置中。过滤器需要将异常重定向到上面定义的异常处理。这是一个例子:

 @Component
public class FilterChainExceptionHandler extends OncePerRequestFilter {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        try {
            filterChain.doFilter(request, response);
        } catch (Exception e) {
            log.error("Spring Security Filter Chain Exception:", e);
            resolver.resolveException(request, response, null, e);
        }
    }
}

然后需要将创建的过滤器添加到 SecurityConfiguration。您需要尽早将其挂接到链中,因为不会捕获前面所有过滤器的异常。就我而言,在 LogoutFilter 之前添加它是合理的。请参阅 官方文档中 的默认过滤器链及其顺序。这是一个例子:

 @Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private FilterChainExceptionHandler filterChainExceptionHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .addFilterBefore(filterChainExceptionHandler, LogoutFilter.class)
            (...)
    }

}

原文由 ssc-hrep3 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题