美文网首页Java
如何在Spring的ExceptionHandler中获取Bod

如何在Spring的ExceptionHandler中获取Bod

作者: 化简为繁 | 来源:发表于2018-03-14 17:15 被阅读0次

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


    可使用的参数类型

    • 一个异常参数。声明一个一般性的异常或者更加具体的异常
    • Request 和/或 response 对象(Servlet API 或 Portlet API)。可以选择一个特定 - request/response的类型,比如ServletRequest / HttpServletRequest
    • Session 对象
    • WebRequest 或 NativeWebRequest
    • Locale
    • InputStream / Reader 访问请求内容
    • OutputStream / Writer 生成响应内容
    • Model

    异常处理方法支持的返回值类型

    • ModelAndView 对象 (Servlet MVC or Portlet MVC)
    • Model 对象
    • Map 对象,
    • View 对象
    • 被解析成一个视图名称的String 值
    • @ResponseBody 注解的方法 (仅限Servlet) 设置响应内容
    • HttpEntity<?> 或 ResponseEntity<?> (仅限Servlet) 设置响应头和响应内容
    • void。方法自己处理了响应。

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

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

    使用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);
           }
       }
    
    1. ExceptionHandler传入ServletRequest,此时的ServletRequest就是ContentCachingRequestWrapper,输出即可
    
        @ExceptionHandler({HttpRequestMethodNotSupportedException.class,
                HttpMessageConversionException.class,
                TypeMismatchException.class})
        public ResponseEntity<Response> returnMediaTypeNotSupportError(Exception ex, ServletRequest request) {
            if (request != null && request instanceof ContentCachingRequestWrapper) {
                ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
                logger.warn("BAD_REQUEST_BODY:{}", StringUtils.toEncodedString(wrapper.getContentAsByteArray(), Charset.forName(wrapper.getCharacterEncoding())));
            }
               .....
    

    相关文章

      网友评论

        本文标题:如何在Spring的ExceptionHandler中获取Bod

        本文链接:https://www.haomeiwen.com/subject/yzofqftx.html