前言:
最近使用springmvc寫了不少rest api, 覺得真是一個好框架. 之前描述的幾篇關於rest api的文章, 其實還是不夠完善. 比如當遇到參數缺失, 類型不匹配的情況時, 直接拋出異常, 返回的內容是400+的錯誤頁面, 而不是json內容, 這讓移動端的調用方很難處理.
本文主要講述對於rest api, springmvc對異常的解決處理方案.
系列整理:
springmvc學習筆記系列的文章目錄:
• idea創建springmvc項目
• 面向移動端的REST API
• Jackson的使用和定制
REST API的設計原則博文
• 移動互聯網實戰—Web Restful API設計和基礎架構
場景構造:
大背景, 我們已借助使用Jackson框架和注解@ResonseBody來實現pojo對象以json形式返回.
先來構造幾個案例, 來描述我們所要解決的問題.
共同的測試代碼:
@Controller @RequestMapping("/math") public class TestController { @RequestMapping(value="/div", method= RequestMethod.GET) @ResponseBody public int div(@RequestParam("a") int a, @RequestParam("b") int b) { // *) div zero error return a / b; } }
1). 場景一(參數缺失, 類型不匹配)
case 1:
http://localhost:8080/math/div?a=10
參數b缺失, 返回400錯誤頁
case 2:
http://localhost:8080/math/div?a=10&b=hehe
參數b類型不對, 類型轉換失敗
我們的希望是, 將這些參數缺少/類型不匹配的異常, 以JSON串的形式返回, 而不是以400的錯誤頁面返回.
2). 場景二(業務代碼拋出異常)
case 1:
http://localhost:8080/math/div/a=10&b=0
發生除零異常
內部拋出業務異常非常常見, 防不勝防, 返回是500+的錯誤頁面.
解決方案:
基於上文的場景, 遇到異常時, 返回的都是400+/500+的錯誤頁面, 一方面客戶端sdk解析和處理麻煩, 另一方面泄露了內部的錯誤細節. 那是否一種辦法攔截異常, 並返回自己定義的錯誤數據格式呢?
答案是肯定的, springmvc引入了織入@ControlAdvice.
其對異常的處理, 非常的方便, 可簡單參考如下sample.
@ControllerAdvice public class RestApiControlAdvice { @ExceptionHandler(value=RuntimeException.class) @ResponseBody public String handle(RuntimeException e) { // *記入異常日志 return e.getMessage(); } @ExceptionHandler(value=Exception.class) @ResponseBody public String handle(Exception e) { // *記入異常日志 return e.getMessage(); } }
通過結合注解@ExceptionHanlder, 來定義具體的異常處理, 以及返回的結果.
這邊需要注意的是, @ExceptionHandler可定義多個, 當多個匹配時, 按編寫最早的處理函數優先處理. 這邊就像try/catch那種常見的情況了, 既順序敏感. 最佳實踐, 需要把處於頂層的異常類擱置到代碼最尾端.
當然對於參數缺失/類型不匹配的處理, 可以如下定義.
@ExceptionHandler(value=MissingServletRequestParameterException.class) @ResponseBody public TResult<Void> handle(MissingServletRequestParameterException e) { return "Miss parameter " + e.getParameterName() + ":" + e.getParameterType(); } @ExceptionHandler(value= TypeMismatchException.class) @ResponseBody public String handle(TypeMismatchException e) { return e.getErrorCode() + ", required type: " + e.getRequiredType() + ", but value: " + e.getValue(); }
業務上的異常代碼, 往往可以抽象出一個異常基類.
總結:
springmvc的入門和上手確實非常快, 但要真正的理解. 確實還是需要花功夫, 這邊只是簡單介紹一下, 並沒有深入源碼. 希望將來有一天有機會講講背后的技術原理.
公眾號&游戲站點:
個人微信公眾號: 木目的H5游戲世界
個人游戲作品集站點, www.mmxfgame.com, 請點擊訪問: http://120.26.221.54/.