目前是用SpringMVC時(shí)马僻,往往使用ExceptionHandler去做Controller層的統(tǒng)一異常處理。
使用ExceptionHandler注解的異常處理方法可以使用很靈活的方法簽名扰藕。
可使用的參數(shù)類型
- 一個(gè)異常參數(shù)。聲明一個(gè)一般性的異常或者更加具體的異常
- Request 和/或 response 對(duì)象(Servlet API 或 Portlet API)逝钥⌒合桑可以選擇一個(gè)特定 - request/response的類型糕再,比如ServletRequest / HttpServletRequest
- Session 對(duì)象
- WebRequest 或 NativeWebRequest
- Locale
- InputStream / Reader 訪問請(qǐng)求內(nèi)容
- OutputStream / Writer 生成響應(yīng)內(nèi)容
- Model
異常處理方法支持的返回值類型
- ModelAndView 對(duì)象 (Servlet MVC or Portlet MVC)
- Model 對(duì)象
- Map 對(duì)象,
- View 對(duì)象
- 被解析成一個(gè)視圖名稱的String 值
- @ResponseBody 注解的方法 (僅限Servlet) 設(shè)置響應(yīng)內(nèi)容
- HttpEntity<?> 或 ResponseEntity<?> (僅限Servlet) 設(shè)置響應(yīng)頭和響應(yīng)內(nèi)容
- void。方法自己處理了響應(yīng)玉转。
如何在異常發(fā)生時(shí)輸出請(qǐng)求
發(fā)生異常時(shí)突想,不僅僅需要輸出異常本身,經(jīng)常還需要根據(jù)Request的具體內(nèi)容來分析究抓、排查問題猾担。
比如HttpRequestMethodNotSupportedException、HttpMessageConversionException等等刺下,這些異常發(fā)生在業(yè)務(wù)代碼處理之前绑嘹,業(yè)務(wù)代碼是無法獲取到request的數(shù)據(jù)的,發(fā)生異常時(shí)如果能夠看到請(qǐng)求body的具體內(nèi)容橘茉,那么處理起來就可以對(duì)癥下藥工腋,事半功倍。
說起來簡單畅卓,做起來卻不是很順當(dāng)擅腰,雖然ExcelptionHandler中可以傳入ServerletRequest作為入?yún)ⅲ荢erverletRequest的inputStream只能被讀取一次髓介,發(fā)生異常的時(shí)候再想去讀取body只能悲催的得到一個(gè)已經(jīng)Closed的Stream惕鼓。
找了一大圈,發(fā)現(xiàn)了一個(gè)有效的方法唐础,感謝StackOverflow -_-~
使用ContentCachingRequestWrapper
- 通過過濾器將ServerletRequest封裝成ContentCachingRequestWrapper箱歧,body被讀取后,會(huì)被它緩存一膨。
@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);
}
}
- ExceptionHandler傳入ServletRequest呀邢,此時(shí)的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())));
}
.....