发生异常时,从ExceptionHandler中获取Body参数进行分析

用SpringMVC时,使用ExceptionHandler去做Controller层的统一异常处理。
使用ExceptionHandler注解的异常处理方法可以使用很灵活的方法签名。

如何在异常发生时输出请求

发生异常时,不仅仅需要输出异常本身,经常还需要根据Request的具体内容来分析、排查问题。
比如HttpRequestMethodNotSupportedException、HttpMessageConversionException等等,这些异常发生在业务代码处理之前,业务代码是无法获取到request的数据的,发生异常时如果能够看到请求body的具体内容,那么处理起来就可以对症下药,事半功倍。
说起来简单,做起来却不是很顺当,虽然ExcelptionHandler中可以传入ServerletRequest作为入参,但是ServerletRequest的inputStream只能被读取一次,发生异常的时候再想去读取body只能悲催的得到一个已经Closed的Stream。

使用ContentCachingRequestWrapper

1,通过过滤器将ServerletRequest封装成ContentCachingRequestWrapper,body被读取后,会被它缓存。

@Component
public class RequestWrapperFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(new ContentCachingRequestWrapper(httpServletRequest), httpServletResponse);
    }
}

2,ExceptionHandler传入ServletRequest,此时的ServletRequest就是ContentCachingRequestWrapper,输出即可

    @ExceptionHandler(value = Exception.class)
    public ResponseEntity<Response> returnMediaTypeNotSupportError(Exception ex, ServletRequest request) {
        if (request != null && request instanceof ContentCachingRequestWrapper) {
            ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
            logger.error("request_body:{}", StringUtils.toEncodedString(wrapper.getContentAsByteArray(), Charset.forName(wrapper.getCharacterEncoding())));
        }
    }
要在全局异常处理中获取方法名和请求参数,并将它们存储到数据库中,可以按照以下步骤进行操作: 1. 创建一个实体类用于存储异常信息和相关数据,例如: ```java @Entity @Table(name = "exception_log") public class ExceptionLog { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "method_name") private String methodName; @Column(name = "request_params") private String requestParams; // 其他字段和方法 } ``` 2. 在全局异常处理器中获取方法名和请求参数,并将它们存储到数据库中。可以使用 AOP 切面来实现这个功能。创建一个切面类并使用 @Aspect 注解标识,然后在切面类中定义异常处理的逻辑。例如: ```java @Aspect @Component public class ExceptionLogAspect { @Autowired private ExceptionLogRepository exceptionLogRepository; @AfterThrowing(pointcut = "execution(* com.example.controller.*.*(..))", throwing = "e") public void handleException(JoinPoint joinPoint, Throwable e) { // 获取方法名 String methodName = joinPoint.getSignature().getName(); // 获取请求参数 String requestParams = Arrays.toString(joinPoint.getArgs()); // 创建 ExceptionLog 对象并保存到数据库 ExceptionLog exceptionLog = new ExceptionLog(); exceptionLog.setMethodName(methodName); exceptionLog.setRequestParams(requestParams); // 其他字段设置 exceptionLogRepository.save(exceptionLog); } } ``` 3. 配置切面类和异常处理器。在 Spring Boot 的配置类中添加 @EnableAspectJAutoProxy 注解启用切面,同在全局异常处理器中添加对应的逻辑处理。例如: ```java @Configuration @EnableAspectJAutoProxy public class AppConfig { // 其他配置 @Bean public ExceptionLogAspect exceptionLogAspect() { return new ExceptionLogAspect(); } @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<?> handleException(Exception e) { // 异常处理逻辑 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal Server Error"); } } } ``` 通过以上步骤,你可以在全局异常处理中获取方法名和请求参数,并将它们存储到数据库中。请根据你的实际需求进行相应的调整和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值