十年網(wǎng)站開發(fā)經(jīng)驗 + 多家企業(yè)客戶 + 靠譜的建站團隊
量身定制 + 運營維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
SpringBoot 統(tǒng)一異常處理
異常和響應(yīng)碼
因為用RESTful設(shè)計的接口, 應(yīng)該用狀態(tài)碼反映請求的錯誤, 不應(yīng)該統(tǒng)一返回200 的狀態(tài)碼, 然后再通過 msg 來描述錯誤. 所以統(tǒng)一異常處理比較關(guān)鍵.
異常一般分為 業(yè)務(wù)異常 和 非業(yè)務(wù)異常
業(yè)務(wù)異常通常返回4xx的狀態(tài)碼
非業(yè)務(wù)異常只需要返回 500 , 提示 服務(wù)器錯誤,請稍候重試
默認(rèn)異常處理
SpringBoot 提供了默認(rèn)的處理異常方式,當(dāng)出現(xiàn)異常時就會默認(rèn)映射到 /error。處理異常的程序在類BasicErrorController 中.
該類提供了兩種異常處理的方法 :
方法 errorHtml 用于處理瀏覽器端請求時出現(xiàn)的異常.
方法 error 用于處理機器客戶端請求時出現(xiàn)的異常。
這兩種請求的的區(qū)別在于請求頭中 Accept 的值 :
值為 text/html 時,方法 errorHtml 執(zhí)行,返回 HTML 頁面。
值為 application/json 時,方法 error 執(zhí)行,返回 json 數(shù)據(jù)。
errorHtml 和 error 兩個方法的源代碼
@RequestMapping(produces = "text/html")
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
HttpStatus status = getStatus(request);
Mapmodel = Collections.unmodifiableMap(getErrorAttributes(
request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
}@RequestMapping @ResponseBody public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); HttpStatus status = getStatus(request); return new ResponseEntity<>(body, status); }
瀏覽器端錯誤頁面
如果想自定義頁面替換這個頁面, 你只需在 /error 文件夾下添加一個表示錯誤頁面的文件。該文件可以是一個靜態(tài)的HTML,也可以使用模板。這個文件的名字應(yīng)該是精確的狀態(tài)碼或者是表示一個系列的模糊名稱。如下:
src/
+- main/
+- java/
| +
+- resources/
+- public/
+- error/
| +- 404.html
+-src/
+- main/
+- java/
| +
+- resources/
+- templates/
+- error/
| +- 5xx.ftl
+-
其背后的原理在于上面提到的 errorHtml 方法。當(dāng)出現(xiàn)異常時,該方法會查詢是否有在 error 文件夾下提供對應(yīng)錯誤狀態(tài)碼的靜態(tài)資源文件,如果有則返回該文件,沒有則返回上小節(jié)講到的白色錯誤標(biāo)簽頁。如果想要知道更詳細(xì)的細(xì)節(jié)請查看相關(guān)源碼。
JSON格式錯誤
當(dāng)請求頭中的Accept的值為 application/json 時,就會返回 json 數(shù)據(jù)了。出現(xiàn)異常時,BasicErrorController 類中的 error 方法將被執(zhí)行。會獲取錯誤信息然后以 Json 格式返回。如下圖:
自定義異常處理
下面有兩種方式自定義異常處理
對于應(yīng)用級別的業(yè)務(wù)異常處理,我們可以通過注解 @ControllerAdvice 或 @RestControllerAdvice 來實現(xiàn)異常處理。但是上面的注解只能捕獲處理應(yīng)用級別的異常,例如 Controller 中拋出自定義的異常。卻不能處理容器級別的異常,例如 Filter 中拋出的異常等。
要想處理容器級別的異常,需要繼承 BasicErrorController 類,重寫 errorHtml 和 error 方法?;蛘邔崿F(xiàn) ErrorController 接口,起到和類 BasicErrorController 相似的作用。
處理應(yīng)用級別異常
下面是返回 JSON 格式的處理類@RestControllerAdvice
br/>@RestControllerAdvice
private static final long serialVersionUID = 1L;
@ExceptionHandler(value = MissingServletRequestParameterException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
return new R<>(null, "缺少參數(shù)");
}
}
@RestControllerAdvice 與 @ControllerAdvice +@ResponseBody 起到的作用是一樣的
注解 @ExceptionHandler 里面的 value 的類是我們捕獲的處理異常, 此類異常會被defaultErrorHandler 方法處理.
@ResponseStatus(HttpStatus.BAD_REQUEST) 注解, 指定了此異常返回的狀態(tài)碼, 因為是缺少參數(shù), 所以返回 400 的狀態(tài)碼
R 類為一個 ResultJSON 類, 把內(nèi)容封裝起來, 一般有 code, meg , data 三個屬性. 返回一個 JSON 字符串
處理容器級別的異常
@ControllerAdvice 注解的異常處理類并不能處理容器級別的異常, 我們可以通過繼承 BasicErrorController 類重寫 errorHtml 或 error 方法,以達(dá)到我們想要的返回結(jié)果。
還可以通過實現(xiàn) ErrorController 接口的方法來實現(xiàn)自定義異常處理,BasicErrorController 類也是實現(xiàn)了 ErrorController 接口,因此這種方式和 BasicErrorController 類有相似作用。實現(xiàn)起來相對麻煩,本文只講解繼承 BasicErrorController 類的方式。
@Controller
public class CustomizeErrorController extends BasicErrorController{
public CustomizeErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties, List errorViewResolvers){
super(errorAttributes, errorProperties, errorViewResolvers);
}
@RequestMapping(produces = {"text/html"})
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = this.getStatus(request);
Map model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
return modelAndView == null ? new ModelAndView("error", model) : modelAndView;
}
@RequestMapping
@ResponseBody
public ResponseEntity
}
該類將會覆蓋 BasicErrorController 類起到處理異常的作用。但這里要注意,如果想要保留對SpringBoot默認(rèn)的對瀏覽器請求的異常處理(也就是根據(jù)異常錯誤狀態(tài)碼返回 error 文件夾下對應(yīng)的錯誤頁面),還需新建一個配置文件 CustomErrorConfiguration
@Configuration@ConditionalOnWebApplication
br/>@ConditionalOnWebApplication
br/>@AutoConfigureBefore({WebMvcAutoConfiguration.class})
public class CustomErrorConfiguration {
private final ServerProperties serverProperties;
private final ListerrorViewResolvers; public CustomErrorConfiguration(ServerProperties serverProperties, ObjectProvider<List<ErrorViewResolver>> errorViewResolversProvider) { this.serverProperties = serverProperties; this.errorViewResolvers = (List)errorViewResolversProvider.getIfAvailable(); } @Bean public CustomizeErrorController customizeErrorController(ErrorAttributes errorAttributes){ return new CustomizeErrorController(errorAttributes, this.serverProperties.getError(),errorViewResolvers); }
}
創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動態(tài)BGP最優(yōu)骨干路由自動選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機房獨有T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動現(xiàn)已開啟,新人活動云服務(wù)器買多久送多久。