使用SpringBoot處理RESTAPI錯誤

導言

SpringBoot提供了一種開箱即用的異常處理機制。的默認實現。ErrorController在捕獲和處理異常方面做得很好。而且,我們仍然可以定義我們自己的@ExceptionHandlerS來捕獲和處理特定的異常。但是,仍有改進的餘地:

即使我們決定使用自定義來處理所有異常@ExceptionHandler,某些異常仍將設法轉義該處理程序和ErrorController將負責異常處理。這@ExceptionHandlerv.V.ErrorController二元性是絕對可以改善的。
有時,默認的錯誤表示看起來有點混亂:

{
  "timestamp": "2018-09-23T15:05:32.681+0000",
  "status": 400,
  "error": "Bad Request",
  "errors": [
    {
      "codes": [
        "NotBlank.dto.name",
        "NotBlank.name",
        "NotBlank.java.lang.String",
        "NotBlank"
      ],
      "arguments": [
        {
          "codes": [
            "dto.name",
            "name"
          ],
          "arguments": null,
          "defaultMessage": "name",
          "code": "name"
        }
      ],
      "defaultMessage": "{name.not_blank}",
      "objectName": "dto",
      "field": "name",
      "rejectedValue": null,
      "bindingFailure": false,
      "code": "NotBlank"
    }
  ],
  "message": "Validation failed for object='dto'. Error count: 1",
  "path": "/"
}

當然,我們可以通過註冊一個自定義來改進這一點。ErrorAttributes實現,但更明智和固執己見(仍然很容易定製)的默認表示將是最好的。

對於驗證錯誤,可以很容易地將約束中的一些參數公開給內插消息。例如,int值可以使用{}佔位符語法但是,其他例外情況並非如此:

public class UserAlreadyExistsException extends RuntimeException {
    // How can I expose this value to the interpolated message?
    private final String username;
    // constructors and getters and setters
}

如果我們有內置的支持應用層錯誤碼所有例外。有時,只需使用適當的http狀態代碼,我們找不到到底出了什麼問題。例如,如果同一個端點上的兩個完全不同的錯誤具有相同的狀態代碼,怎麼辦?

有待改進的餘地

這個errors-spring-boot-starter提供一種Bootiful、一致和固執己見的方法來處理各種異常。基於SpringBoot的異常處理機制,errors-spring-boot-starter報盤:

1,處理所有異常的一致方法–不管是驗證/綁定錯誤還是自定義域特定的錯誤,甚至是與Spring相關的錯誤。所有這些都將由WebErrorHandler實現處理(不再有ErrorController VS@ExceptionHandler)
2,對應用程序特定錯誤代碼的內置支持,同樣適用於所有可能的錯誤.
3,使用MessageSource的簡單錯誤消息插值。
4,可自定義的HTTP錯誤表示形式。
5,公開從異常到錯誤消息的參數。

默認錯誤表示

默認情況下,錯誤將是具有以下模式的JSON結果:


// For each error, there is a code/messsge combination in the errors array
{
  "errors": [
    {
      "code": "first_error_code",
      "message": "1st error message"
    }
  ]
}

爲了自定義此表示,只需註冊HttpErrorAttributesAdapter。

一致錯誤處理方法

所有異常將由WebErrorHandler執行。默認情況下,這個啓動程序會參考一些內置的內容。WebErrorHandler方法來處理下列特定異常:

1,處理所有驗證/綁定異常的實現。
2,類註釋的自定義異常的實現。@ExceptionMapping.
3,一個處理SpringMVC特定異常的實現。
4,如果SpringSecurity在類路徑上,則是一個處理SpringSecurity特定異常的實現。
通過實現WebErrorHandler實現.

內置錯誤代碼支持

雖然在RESTfulAPI中使用適當的HTTP狀態代碼是一種推薦的方法,但有時我們需要更多的信息來了解到底出了什麼問題。這裏是錯誤碼進來。您可以將錯誤代碼視爲機器可讀性錯誤描述。每個異常都可以映射到至少一個錯誤代碼。

這個異常到錯誤代碼映射根據異常類型而有所不同:

驗證錯誤代碼將從message 相應約束註釋的屬性,例如@NotBlank(message = “name.required”).
這個errorCode屬性爲帶註釋的異常。@ExceptionMapping如下所示:

@ExceptionMapping(statusCode = BAD_REQUEST, errorCode = "user.already_exists")
public class UserAlreadyExistsException extends RuntimeException {}

自定義實現的代碼WebErrorHandler :

public class ExistedUserHandler implements WebErrorHandler {
    @Override
    public boolean canHandle(Throwable exception) {
        return exception instanceof UserAlreadyExistsException;
    }
    @Override
    public HandledException handle(Throwable exception) {   
        return new HandledException("user.already_exists", BAD_REQUEST, null);
    }
}

揭露論點

與SpringBoot一樣,您可以從約束註釋傳遞驗證參數。@Min(value = 18, message = “age.min”),到擬內插信息:

age.min = The minimum age is {0}!

此外,爲了支持驗證錯誤的此特性,我們使用@ExposeAsArg 註釋例如,如果我們要在以下消息中指定已經使用的用戶名:

user.already_exists=Another user with the '{0}' username already exists

你可以寫:


@ExceptionMapping(statusCode = BAD_REQUEST, errorCode = "user.already_exists")
public class UserAlreadyExistsException extends RuntimeException {
    @ExposeAsArg(0) private final String username;
    // constructor
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章