重写Spring MVC的异常处理来提供自定义错误消息

Spring MVC会自动把内部出现的异常转换为对应的HTTP状态码并带上相关错误信息,最近需要在生产环境中隐藏详细错误信息

Spring默认使用了DefaultHandlerExceptionResolver,它会捕捉一些特定的异常并将其转换为对应的HTTP状态码,具体如下:

Exception HTTP Status Code
HttpRequestMethodNotSupportedException 405 (SC_METHOD_NOT_ALLOWED)
HttpMediaTypeNotSupportedException 415 (SC_UNSUPPORTED_MEDIA_TYPE)
HttpMediaTypeNotAcceptableException 406 (SC_NOT_ACCEPTABLE)
MissingPathVariableException 500 (SC_INTERNAL_SERVER_ERROR)
MissingServletRequestParameterException 400 (SC_BAD_REQUEST)
ServletRequestBindingException 400 (SC_BAD_REQUEST)
ConversionNotSupportedException 500 (SC_INTERNAL_SERVER_ERROR)
TypeMismatchException 400 (SC_BAD_REQUEST)
HttpMessageNotReadableException 400 (SC_BAD_REQUEST)
HttpMessageNotWritableException 500 (SC_INTERNAL_SERVER_ERROR)
MethodArgumentNotValidException 400 (SC_BAD_REQUEST)
MissingServletRequestPartException 400 (SC_BAD_REQUEST)
BindException 400 (SC_BAD_REQUEST)
NoHandlerFoundException 404 (SC_NOT_FOUND)
AsyncRequestTimeoutException 503 (SC_SERVICE_UNAVAILABLE)

如果需要自定义响应中的消息,则可以继承ResponseEntityExceptionHandler并且标记为ControllerAdvice

1
2
@ControllerAdvice
class GlobalRestExceptionHandler : ResponseEntityExceptionHandler()

ResponseEntityExceptionHandler通过handleException这个方法来catch各种异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Nullable
public final ResponseEntity<Object> handleException(Exception ex, WebRequest request) throws Exception {
HttpHeaders headers = new HttpHeaders();

if (ex instanceof HttpRequestMethodNotSupportedException) {
HttpStatus status = HttpStatus.METHOD_NOT_ALLOWED;
return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, headers, status, request);
}
else if (ex instanceof HttpMediaTypeNotSupportedException) {
HttpStatus status = HttpStatus.UNSUPPORTED_MEDIA_TYPE;
return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, headers, status, request);
}
else if (ex instanceof HttpMediaTypeNotAcceptableException) {
HttpStatus status = HttpStatus.NOT_ACCEPTABLE;
return handleHttpMediaTypeNotAcceptable((HttpMediaTypeNotAcceptableException) ex, headers, status, request);
}
else if (ex instanceof MissingPathVariableException) {
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
return handleMissingPathVariable((MissingPathVariableException) ex, headers, status, request);
}
···
else {
// Unknown exception, typically a wrapper with a common MVC exception as cause
// (since @ExceptionHandler type declarations also match first-level causes):
// We only deal with top-level MVC exceptions here, so let's rethrow the given
// exception for further processing through the HandlerExceptionResolver chain.
throw ex;
}
}

然后,对于每种特定的方法都会有一个方法来handle,比如:

1
2
3
4
5
protected ResponseEntity<Object> handleConversionNotSupported(
ConversionNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

return handleExceptionInternal(ex, null, headers, status, request);
}

所有的这些方法最后会调用handleExceptionInternal来生成一个ResponseEntity:

1
2
3
4
5
6
7
8
protected ResponseEntity<Object> handleExceptionInternal(
Exception ex, @Nullable Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {

if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {
request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST);
}
return new ResponseEntity<>(body, headers, status);
}

可以看到,所有handle方法的默认实现在调用handleExceptionInternal时传入的body参数都是null,所以如果只是单纯的继承ResponseEntityExceptionHandler而不重写任何方法的话,出错之后会返回对应的错误代码,但是不会返回任何消息。

如果要为特定的状态码提供自定义的消息,就需要重写状态码对应的异常的handle方法,比如:

1
2
3
4
5
6
@ControllerAdvice
class GlobalRestExceptionHandler : ResponseEntityExceptionHandler() {
override fun handleHttpMessageNotReadable(ex: HttpMessageNotReadableException, headers: HttpHeaders, status: HttpStatus, request: WebRequest): ResponseEntity<Any> {
return super.handleExceptionInternal(ex, "TEST", headers, status, request)
}
}

这时候出错后就会返回一个400的相应,并且消息是TEST

Kubernetes下Jenkins CI的搭建 简单设计

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×