dibugger
dibugger

Reputation: 576

Spring Boot error controller retrieve original request

By default Spring Boot maps /error to BasicErrorController. I want to log the exception along with the request that causes the exception. How can I get the original request in BasicErrorController or a new CustomErrorController. It seems that Spring Boot will make a new request to /error when an exception is thrown and the orginal request info is gone or no way to map the error with the original request. enter image description here

Upvotes: 13

Views: 6378

Answers (5)

VZoli
VZoli

Reputation: 602

@Override
@ResponseStatus(HttpStatus.BAD_REQUEST)
protected ResponseEntity<Object> handleMethodArgumentNotValid(
        MethodArgumentNotValidException exception,
        HttpHeaders headers,
        HttpStatus status,
        WebRequest request) {
    OriginalRequestObject originalRequest = (OriginalRequestObject) exception.getBindingResult().getTarget();
    ErrorResponse errorResponse = new ErrorResponse(
            status.value(),
            originalRequest.getId() + " " + exception.getMessage());
    return ResponseEntity.status(status).body(myErrorResponse);
}

Upvotes: 0

Jim Cox
Jim Cox

Reputation: 1044

Here is a working example:

@RestController
public class MyErrorController implements ErrorController {

    private static final Logger LOG = LoggerFactory.getLogger(MyErrorController.class);

    private static final String PATH = "/error";

    private final ErrorAttributes errorAttributes;

    public MyErrorController(ErrorAttributes errorAttributes) {
        this.errorAttributes = errorAttributes;
    }

    @RequestMapping(value = PATH)
    public ErrorDTO error(WebRequest webRequest, HttpServletRequest httpServletRequest) {

        // Appropriate HTTP response code (e.g. 404 or 500) is automatically set by Spring.
        Map<String, Object> attrs = errorAttributes.getErrorAttributes(webRequest, ErrorAttributeOptions.defaults());

        LOG.warn("Forwarded Error Request: {} ", attrs.get("path"), (Throwable)
                httpServletRequest.getAttribute("javax.servlet.error.exception"));

        ErrorDTO dto = new ErrorDTO();
        dto.message = (String) attrs.get("error");
        dto.path = (String) attrs.get("path");
        dto.timestamp = attrs.get("timestamp").toString();
        return dto;
    }
 }

Upvotes: 0

meadlai
meadlai

Reputation: 935

Get it by:

String url = (String) request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI);

Upvotes: 12

ravinikam
ravinikam

Reputation: 3696

If you are using controller advice to handle your exceptions then method with @ExceptionHandler can inject request as parameter, something like :

@ControllerAdvice
public class YourExceptionHandler
{
    @ExceptionHandler
    public ResponseEntity handleExceptions(HttpServletRequest request, Exception exception)
    {
        // use request to populate error object with details like requestId
        LOGGER.debug(String.valueOf(request));
        LOGGER.error(exception.getMessage(), exception);
     }
}

Upvotes: 0

dibugger
dibugger

Reputation: 576

To avoid any misleading information, Spring Boot DOES NOT make a new request to /error endpoint. Instead, it wraps the exception in the original request and forwards it to /error endpoint. The request will be processed by BasicErrorHandler if you don't provide a custom error handler.

In this case, if you are using an interceptor, the interceptor will be invoked twice - one for the original request and the other for the forwarded request.

To retrieve the original request information, please look into the forwarded request's attributes. Basically, you can get the error message from these attributes javax.servlet.error.message, javax.servlet.error.status_code, org.springframework.web.servlet.DispatcherServlet.EXCEPTION.

And these are some resources that are related to error handling in Spring Boot:

Upvotes: 5

Related Questions