[英]Spring Boot @RestControllerAdvice not Catching Custom Exceptions
[英]Spring Boot - Global Custom Exception Handling Mechanism using RestControllerAdvice
我正在將Spring Boot用於Restful Web Services。
嘗試建立一個依賴於@RestControllerAdvice的全局自定義異常處理機制,該機制可以處理已知但未知的異常。
的pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
GlobalControllerExceptionHandler:
@RestControllerAdvice
public class GlobalControllerExceptionHandler {
private static final Logger LOG = Logger.getLogger(GlobalControllerExceptionHandler.class);
@ExceptionHandler(value = { ConstraintViolationException.class })
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiErrorResponse constraintViolationException(ConstraintViolationException ex) {
LOG.error(ex.getCause().toString());
return new ApiErrorResponse(400, "Bad Request");
}
@ExceptionHandler(value = { NoHandlerFoundException.class })
@ResponseStatus(HttpStatus.NOT_FOUND)
public ApiErrorResponse noHandlerFoundException(Exception ex) {
LOG.error(ex.getCause().toString());
return new ApiErrorResponse(404, "Resource Not Found");
}
@ExceptionHandler(value = { Exception.class })
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiErrorResponse unknownException(Exception ex) {
LOG.error(ex.getCause().toString());
return new ApiErrorResponse(500, "Internal Server Error");
}
}
ApiErrorResponse:
public class ApiErrorResponse {
private int status;
private String message;
public ApiErrorResponse(int status, String message) {
this.status = status;
this.message = message;
}
public int getStatus() {
return status;
}
public String getMessage() {
return message;
}
@Override
public String toString() {
return new ToStringBuilder(this).append(status)
.append(message)
.toString();
}
}
問題是當我使用第3方庫執行某項操作時,未知異常可能是404,但返回為500!
例如,將ElasticSearch與未知索引一起使用(故意查看Exception的類型):
{
"timestamp": 1501236796640,
"status": 500,
"error": "Internal Server Error",
"exception": "org.elasticsearch.client.ResponseException",
"message": "POST http://localhost:9200/fn3r4343/_search?pretty=true: HTTP/1.1 404 Not Found"
{
"error": {
"root_cause": [
{
"type": "index_not_found_exception",
"reason": "no such index",
"resource.type": "index_or_alias",
"resource.id": "fn3r4343",
"index_uuid": "_na_",
"index": "fn3r4343"
}
],
"type": "index_not_found_exception",
"reason": "nosuchindex",
"resource.type": "index_or_alias",
"resource.id": "fn3r4343",
"index_uuid": "_na_",
"index": "fn3r4343"
}
{ "root_cause" :
[
{
"type" :"index_not_found_exception",
"reason" : no such index", "resource.type" : "index_or_alias",
"resource.id" : "fn3r4343",
"index_uuid" : "_na_",
"index" : "fn3r4343"
}
],
[
{
"type" : "index_not_found_exception",
"reason" : "no such index",
"resource.type" : "index_or_alias",
"resource.id" : "fn3r4343",
"index_uuid" : "_na_",
"index" : "fn3r4343"
},
"status": 404
]
}
"path": "/myapp/search"
}
可以看到,它返回為HTTP 500狀態,但是在有效負載中返回的是真正的HTTP 404!
我要返回的是這樣的:
{
"message" : "Index Not Found Exception",
"status" : "HTTP 404"
}
對於已知的HTTP 404異常:
{
"message" : "Not Found",
"status" : "HTTP 404"
}
是否有良好的實踐/機制來使用RestControllerAdvice來捕獲任何類型的Exception,並將響應自定義為JSON格式,這對於使用REST API的客戶端而言是可讀/有用的?
這篇文章並不是專門針對Elastic Search,而是通過嘗試使用@RestControllerAdvice處理任何類型的Exception來如何為客戶端應用程序提供正確的響應...
引發的基礎異常是org.elasticsearch.client.ResponseException
(您可能正在使用低級REST客戶端)。
因此,在您的建議中,您需要為該異常添加處理程序並返回基礎狀態代碼:
@ExceptionHandler(value = { ResponseException.class })
public ApiErrorResponse noHandlerFoundException(Exception ex) {
LOG.error(ex.getCause().toString());
int status = ((ResponseException) ex).getResponse().getStatusLine().getStatusCode();
return new ApiErrorResponse(status, "<some message depending on status code>");
}
我認為這對下課應該有所幫助:
@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = {MyException.class})
protected ResponseEntity<Object> handleConflict(Exception exception, WebRequest request)
{
FinalResponse response = new FinalResponse()//Define this Bean in a way that it contains all required paramteres to be sent in response when exception occurs
response.setErrorCd("123");
response.setMessage("Exception while processing.");
if (exception instanceof MyException)
{
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
else
{
return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.