【问题标题】:@ControllerAdvice doesn't handle exceptions@ControllerAdvice 不处理异常
【发布时间】:2018-07-13 01:01:40
【问题描述】:

我正在使用 Spring Boot 1.5.9 来开发我的应用程序。我需要实现 jwt 身份验证,并且我使用了 jjwt 库。以下代码来自我的自定义身份验证安全过滤器,它继承自 OncePerRequestFilter。在这里,我尝试从令牌中解析用户名,当用户名自动解析时经过 jwt 验证并检查令牌过期。我调试它并且它工作正常,所以我接下来想向客户端应用程序发送正确的消息,为什么身份验证失败。我想抛出一个 ExpiredJwtException 并使用我格式化输出的控制器建议来处理它。

这里是异常抛出:

try {
    username = jwtTokenService.getUsername(authToken);
} catch (IllegalArgumentException e) {
    logger.error("an error occured during getting username from token", e);
} catch (ExpiredJwtException e) {
    logger.warn("the token is expired and not valid anymore", e);
    throw new ExpiredJwtException(e.getHeader(), e.getClaims(), e.getMessage());
}

这是我的控制器建议,JwtException 是我抛出的 ExpiredJwtException 的基类,因此它应该可以工作。我也试过直接在ExceptionHandler中使用ExpiredJwtException,但效果不佳。接下来我想用同样的方式处理另一个异常。

@ControllerAdvice
public class GlobalControllerExceptionHandler {

    @ExceptionHandler(Exception.class)
    public @ResponseBody
    ResponseEntity<Map<String, Object>> handleException(Exception ex) {
        Map<String, Object> errorInfo = new HashMap<>();
        errorInfo.put("message", ex.getMessage());
        errorInfo.put("status", HttpStatus.BAD_REQUEST);
        errorInfo.put("status_code", HttpStatus.BAD_REQUEST.value());
        return new ResponseEntity<>(errorInfo, HttpStatus.BAD_REQUEST);
    }


    @ExceptionHandler(JwtException.class)
    //@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
    public @ResponseBody
    ResponseEntity handleJwtException(JwtException ex) {
        Map<String, Object> errorInfo = new HashMap<>();
        errorInfo.put("message", ex.getLocalizedMessage());
        errorInfo.put("status", HttpStatus.UNPROCESSABLE_ENTITY);
        errorInfo.put("status_code", HttpStatus.UNPROCESSABLE_ENTITY.value());
        return new ResponseEntity<>(errorInfo, HttpStatus.UNPROCESSABLE_ENTITY);
    }

}

这是我的文件夹结构:

我只想返回 4xx 状态的响应,但是当我的异常被抛出时,我总是得到 5xx 内部错误。你能告诉我我的代码有什么问题吗?感谢您的建议。

【问题讨论】:

  • 是否调用了任何异常处理程序方法?
  • @Synch 我尝试了另一个异常,例如运行时,也没有处理任何事情
  • 你能把你的第一个代码 sn-p 的类和方法贴出来吗?

标签: java spring spring-boot


【解决方案1】:

我也遇到过 RestControllerAdivce 没有处理异常的问题,问题是通知方法只能在其签名中包含那些异常抛出方法具有或可以提供的参数。我的 AOP 方法无法访问 Headers,因此它无法将 Headers 提供给 RestControllerAdivce 方法。一旦我在没有 Headers 作为参数的 RestController 中创建了一个新的异常处理程序方法,RestControllerAdivce 就开始按预期工作。 Detials here

【讨论】:

    【解决方案2】:

    让您的控制器扩展 ResponseEntityExceptionHandler 并让您的异常处理方法以 WebRequest 作为参数

    然后把你的返回值改成这个

    return handleExceptionInternal(ex, errorInfo, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
    

    HttpStatus.BAD_REQUEST 可以更改为任意 40 倍误差

    Exception.class 的示例

    @ExceptionHandler(value = { Exception.class })
    protected ResponseEntity<Object> handleUncaughtException(Exception ex, WebRequest request) {
    
      String message = "Something bad happened";
    
      return handleExceptionInternal(ex, message, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
    }
    

    根据这个Make simple servlet filter work with @ControllerAdvice,您可以创建一个自定义处理程序。

    然后将您的新处理程序添加到您的WebSecurityConfigurerAdapter

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CustomHandler());
    }
    

    【讨论】:

    • 很抱歉,但不起作用...我仍然收到内部服务器错误,并且控制器建议未命中。
    • 从我读到的ControllerAdviceonly 适用于从@Controllers 抛出的异常。您是在控制器或控制器调用的服务中抛出这些异常吗?
    • 也请看这个,它也可能会导致解决方案stackoverflow.com/questions/30335157/…
    • 看起来像我需要的...我实现了自定义 HandlerInterceptor ...但可以告诉我如何将它添加到我的配置中吗?我正在使用 WebSecurityConfigurerAdapter ...可以在此处添加吗?
    • 我在原帖中添加了操作方法
    【解决方案3】:

    如果在过滤器中抛出异常,则不涉及Springs异常处理(@ControllerAdvice@ExceptionHandler)。 您需要在过滤器中捕获所有异常并直接使用ServletResponse

    据我了解 - 过滤器 是低级逻辑(在 spring 基础架构之前处理请求),但您可以有一个解决方法,例如包装链接并捕获所有 RuntimeExceptions 的特定过滤器。 (看起来很麻烦,但没有其他解决方案)。

    如果你想有一个特定的登录来创建你的异常对象 - 覆盖 ErrorAttributes bean。它将允许您对所有应用程序异常有一个单一的视图。

    直接指定http响应状态使用
    httpServletResponse.setStatus(... your status code ...);

    【讨论】:

    • 您的解决方案对我不起作用,否则您对过滤器链和异常的处理是正确的...... T 发现了这个,但我不知道如何使用该处理程序......你能帮我解决这个问题吗? stackoverflow.com/questions/30335157/…
    • 添加一个拦截器来处理异常也不是最好的主意。 ` throw new ExpiredJwtException(e.getHeader(), e.getClaims(), e.getMessage());`.将所有这些直接传递给 ServletResponse 有什么问题? servletResponse.sendError(code, e.getMessage())
    • 我还有一个想法……省略安全过滤器并在控制器中解析和检查请求标头是一种好习惯?接下来我可以将逻辑转移到服务中并处理异常。
    • 这是个糟糕的主意,丹尼斯。请尊重代码中的 SingleResponsibilty。
    猜你喜欢
    • 2014-08-26
    • 1970-01-01
    • 2022-10-14
    • 2017-11-23
    • 2020-12-02
    • 2019-06-04
    • 2019-06-23
    • 1970-01-01
    相关资源
    最近更新 更多