如何在Spring的ExceptionHandler中獲取Body

目前是用SpringMVC時,往往使用ExceptionHandler去做Controller層的統(tǒng)一異常處理。
使用ExceptionHandler注解的異常處理方法可以使用很靈活的方法簽名。


可使用的參數(shù)類型

  • 一個異常參數(shù)。聲明一個一般性的異?;蛘吒泳唧w的異常
  • Request 和/或 response 對象(Servlet API 或 Portlet API)??梢赃x擇一個特定 - request/response的類型,比如ServletRequest / HttpServletRequest
  • Session 對象
  • WebRequest 或 NativeWebRequest
  • Locale
  • InputStream / Reader 訪問請求內(nèi)容
  • OutputStream / Writer 生成響應(yīng)內(nèi)容
  • Model

異常處理方法支持的返回值類型

  • ModelAndView 對象 (Servlet MVC or Portlet MVC)
  • Model 對象
  • Map 對象,
  • View 對象
  • 被解析成一個視圖名稱的String 值
  • @ResponseBody 注解的方法 (僅限Servlet) 設(shè)置響應(yīng)內(nèi)容
  • HttpEntity<?> 或 ResponseEntity<?> (僅限Servlet) 設(shè)置響應(yīng)頭和響應(yīng)內(nèi)容
  • void。方法自己處理了響應(yīng)。

如何在異常發(fā)生時輸出請求

發(fā)生異常時,不僅僅需要輸出異常本身,經(jīng)常還需要根據(jù)Request的具體內(nèi)容來分析、排查問題。
比如HttpRequestMethodNotSupportedException、HttpMessageConversionException等等,這些異常發(fā)生在業(yè)務(wù)代碼處理之前,業(yè)務(wù)代碼是無法獲取到request的數(shù)據(jù)的,發(fā)生異常時如果能夠看到請求body的具體內(nèi)容,那么處理起來就可以對癥下藥,事半功倍。
說起來簡單,做起來卻不是很順當,雖然ExcelptionHandler中可以傳入ServerletRequest作為入?yún)?,但是ServerletRequest的inputStream只能被讀取一次,發(fā)生異常的時候再想去讀取body只能悲催的得到一個已經(jīng)Closed的Stream。
找了一大圈,發(fā)現(xiàn)了一個有效的方法,感謝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())));
        }
           .....
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,527評論 19 139
  • 這部分主要是與Java Web和Web Service相關(guān)的面試題。 96、闡述Servlet和CGI的區(qū)別? 答...
    雜貨鋪老板閱讀 1,501評論 0 10
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,633評論 18 399
  • 從三月份找實習到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,783評論 11 349
  • 不知不覺間…我好像喜歡上了他 開始對他的一舉一動都十分關(guān)注 就連他每次走過我的窗前 我都會抬起頭 癡癡的望著他 看...
    舊顏難忘閱讀 155評論 0 0

友情鏈接更多精彩內(nèi)容