spring boot override default REST exception handle

2020-06-16 09:05发布

问题:

I am not able to override default spring boot error response in REST api. I have following code

@ControllerAdvice
@Controller
class ExceptionHandlerCtrl {

    @ResponseStatus(value=HttpStatus.UNPROCESSABLE_ENTITY, reason="Invalid data")
    @ExceptionHandler(BusinessValidationException.class)
    @ResponseBody
    public ResponseEntity<BusinessValidationErrorVO> handleBusinessValidationException(BusinessValidationException exception){
        BusinessValidationErrorVO vo = new BusinessValidationErrorVO()
        vo.errors = exception.validationException
        vo.msg = exception.message
        def result =  new ResponseEntity<>(vo, HttpStatus.UNPROCESSABLE_ENTITY);
        result

    }

Then in my REST api I am throwing this BusinessValidationException. This handler is called (I can see it in debugger) however I still got default spring boot REST error message. Is there a way to override and use default only as fallback? Spring Boot version 1.3.2 with groovy. Best Regards

回答1:

Remove @ResponseStatus from your method. It creates an undesirable side effect and you don't need it, since you are setting HttpStatus.UNPROCESSABLE_ENTITY in your ResponseEntity.

From the JavaDoc on ResponseStatus:

Warning: when using this annotation on an exception class, or when setting the reason attribute of this annotation, the HttpServletResponse.sendError method will be used.

With HttpServletResponse.sendError, the response is considered complete and should not be written to any further. Furthermore, the Servlet container will typically write an HTML error page therefore making the use of a reason unsuitable for REST APIs. For such cases it is preferable to use a ResponseEntity as a return type and avoid the use of @ResponseStatus altogether.



回答2:

I suggest you to read this question: Spring Boot REST service exception handling

There you can find some examples that explain how to combine ErrorController/ ControllerAdvice in order to catch any exception.

In particular check this answer:

https://stackoverflow.com/a/28903217/379906

You should probably remove the annotation @ResponseStatus from the method handleBusinessValidationException.

Another way that you have to rewrite the default error message is using a controller with the annotation @RequestMapping("/error"). The controller must implement the ErrorController interface.

This is the error controller that I use in my app.

@RestController
@RequestMapping("/error")
public class RestErrorController implements ErrorController
{
    private final ErrorAttributes errorAttributes;

    @Autowired
    public MatemoErrorController(ErrorAttributes errorAttributes) {
        Assert.notNull(errorAttributes, "ErrorAttributes must not be  null");
    this.errorAttributes = errorAttributes;
  }

@Override
public String getErrorPath() {
    return "/error";
}

@RequestMapping
public Map<String, Object> error(HttpServletRequest aRequest) {

    return getErrorAttributes(aRequest, getTraceParameter(aRequest));
}

private boolean getTraceParameter(HttpServletRequest request) {
    String parameter = request.getParameter("trace");
    if (parameter == null) {
        return false;
    }
    return !"false".equals(parameter.toLowerCase());
}

private Map<String, Object> getErrorAttributes(HttpServletRequest  aRequest, boolean includeStackTrace)
{
    RequestAttributes requestAttributes = new  ServletRequestAttributes(aRequest);
    return errorAttributes.getErrorAttributes(requestAttributes,  includeStackTrace);
}  }