如何正确处理SpringBoot异常,避免其冒泡至服务器日志?
我有一个RestController会抛出自定义异常BoogyException,该异常继承自RuntimeException。
RestController代码:
@RestController public class Test { @GetMapping(path = "/test") public ResponseEntity<String> myTest() { throw new BoogyException("I am a boog exception."); } }
BoogyException代码:
public class BoogyException extends RuntimeException { public BoogyException(Exception exception) { // 省略实现 } }
我通过@RestControllerAdvice类映射BoogyException并返回ResponseEntity:
@RestControllerAdvice public class MotherExceptionHandler { @ExceptionHandler(value = { BoogyException.class}) public ResponseEntity<MyJsonExcp> handleBoogyException(final Exception ex) { // 省略实现 } }
MyJsonExcp是带有Jackson注解的简单POJO。当RestController抛出BoogyException时,我能得到正确的JSON格式响应,但WildFly服务器日志中仍会记录一条DEBUG级别的RuntimeException:
DEBUG [io.undertow.request.error-response] (default task-2) Setting error code 500 for exchange HttpServerExchange{ GET /api/test request {cache-control=[max-age=0], accept-encoding=[gzip, deflate, br], ... X-Frame-Options=[SAMEORIGIN]}}: java.lang.RuntimeException at io.undertow.server.HttpServerExchange.setStatusCode(HttpServerExchange.java:1410) ...(省略后续栈跟踪)
看起来SpringBoot将我的自定义异常作为RuntimeException冒泡到了服务器日志中,请问有没有办法阻止这种情况?(使用SpringBoot 2.7.0版本)
解决方案
1. 修正异常处理器的参数与状态码设置
将异常处理器的参数改为具体的BoogyException,同时设置明确的业务状态码(避免默认的500触发Undertow的错误日志),明确告知Spring该异常已被完全处理:
@ExceptionHandler(BoogyException.class) public ResponseEntity<MyJsonExcp> handleBoogyException(final BoogyException ex) { MyJsonExcp errorResponse = new MyJsonExcp(); errorResponse.setMessage(ex.getMessage()); // 根据业务场景设置合适的状态码,比如400(Bad Request) return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); }
2. 补充自定义异常的构造方法
当前BoogyException仅实现了接收Exception的构造方法,但代码中抛出的是带字符串消息的实例,需要补充对应构造方法避免异常包装问题:
public class BoogyException extends RuntimeException { public BoogyException(String message) { super(message); } public BoogyException(Exception exception) { super(exception); } }
3. 调整Undertow的日志级别
如果确认异常已被正确处理,只是Undertow的DEBUG日志冗余,可以在application.properties中修改对应日志的级别,避免记录这类调试信息:
logging.level.io.undertow.request.error-response=INFO
4. 清除请求中的异常标记
如果上述方法无效,可以在异常处理器中手动清除请求上下文的异常,阻止Undertow感知到未处理异常:
@ExceptionHandler(BoogyException.class) public ResponseEntity<MyJsonExcp> handleBoogyException(final BoogyException ex, HttpServletRequest request) { MyJsonExcp errorResponse = new MyJsonExcp(); errorResponse.setMessage(ex.getMessage()); // 清除请求中的异常记录 request.setAttribute("javax.servlet.error.exception", null); return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); }
内容的提问来源于stack exchange,提问作者MFH

