弹簧启动 休息 以空body响应我的@ControllerAdvice中覆盖的例外情况以外的异常



我有一个扩展 ResponseEntityExceptionHandler 的@ControllerAdvice,作为我控制 API 调用工作流中引发的任何异常的标准响应的尝试。

没有控制器的建议。我得到了由 spring 生成的基于 HTML 的通用响应,其中包含正确的响应标头。但是当我添加我的@ControllerAdvice时,Spring 不会使用通用错误正文进行响应。正文为空,具有正确的响应标头

@Override
protected ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
String erroMessage = "Required Parameter: '"+ex.getParameterName()+"' was not available in the request.";
TrsApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, erroMessage, ex, ApiErrorCode.INVALID_REQUEST);
return buildResponseEntity(apiError);
}

因此,现在,如果请求中缺少必需的参数,该流会很好地触发我被覆盖的实现,并使用描述错误的 JSON 有效负载进行响应。但是,在任何其他异常的情况下,如HttpMediaTypeNotAcceptException,spring会以空体响应。

在我添加我的建议之前,Spring 正在用通用的错误响应来响应。我是春季启动生态系统的新手。需要帮助了解这是否是预期行为,或者是否有更好的方法来实现集中式错误处理。

我想我在控制器建议类扩展ResponeEntityExceptionHandler时找到了吞咽身体的解决方案。在我的情况下,设置如下所示:

@ControllerAdvice
@Slf4j
class GlobalExceptionHandlers extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException exception,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
// logic that creates apiError object (object with status, message, errorCode, etc)
//...
return handleExceptionInternal(exception, apiError, headers, status, request);
}

这对于类MethodArgumentNotValidException例外情况就像一个魅力.但它破坏了ResponseEntityExceptionHandler处理的所有其他异常,并为它们返回了空的响应体。

但是修复很容易,只需从ResponseEntityExceptionHandler覆盖handleExceptionInternal

@ControllerAdvice
@Slf4j
class GlobalExceptionHandlers extends ResponseEntityExceptionHandler {
/// ... code from previous snippet
@Override
protected ResponseEntity<Object> handleExceptionInternal(
Exception exception, 
Object body, 
HttpHeaders headers, 
HttpStatus status, 
WebRequest request) {
// for all exceptions that are not overriden, the body is null, so we can
// just provide new body based on error message and call super method
var apiError = Objects.isNull(body) 
? new ApiError(status, exception.getMessage()) // <-- 
: body;
return super.handleExceptionInternal(exception, apiError, headers, status, request);
}
}

这是预期行为。查看类 ResponseEntityExceptionHandler 的源代码。

@ExceptionHandler({
org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException.class,
HttpRequestMethodNotSupportedException.class,
HttpMediaTypeNotSupportedException.class,
HttpMediaTypeNotAcceptableException.class,
MissingPathVariableException.class,
MissingServletRequestParameterException.class,
ServletRequestBindingException.class,
ConversionNotSupportedException.class,
TypeMismatchException.class,
HttpMessageNotReadableException.class,
HttpMessageNotWritableException.class,
MethodArgumentNotValidException.class,
MissingServletRequestPartException.class,
BindException.class,
NoHandlerFoundException.class,
AsyncRequestTimeoutException.class
})
public final ResponseEntity<Object> handleException(Exception ex, WebRequest request) {

所有这些异常都是在没有响应正文的情况下处理的。 调用一个常用方法:

//second parameter is body which is null
handleExceptionInternal(ex, null, headers, status, request)

如果您需要以不同的方式处理特定异常,请覆盖它们,例如我想为HttpMessageNotReadableException发送自定义响应

@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
HttpHeaders headers, HttpStatus status, WebRequest request)
{
logger.error("handleHttpMessageNotReadable()", ex);
ValidationErrors validationErrors = null;
if (ex.getRootCause() instanceof InvalidFormatException) {
InvalidFormatException jacksonDataBindInvalidFormatException = (InvalidFormatException) ex.getRootCause();
validationErrors = new ValidationErrors(jacksonDataBindInvalidFormatException.getOriginalMessage());
}
headers.add("X-Validation-Failure", "Request validation failed !");
return handleExceptionInternal(ex, validationErrors, headers, status, request);
}

使用 @ControllerAdvice 后,您需要定义通用异常结构。

@ResponseBody
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse generationExceptionHandler(Exception e){
log.info("Responding INTERNAL SERVER ERROR Exception");
return new ErrorResponse(ServiceException.getSystemError());
}

相关内容

最新更新