SpringBoot-ErrorController

Springboot 기본 오류 처리


SpringBoot 소스 코드에 이러한 ErrorController가 있습니다. SpringMvc의 잘못된 Mapping을 처리하기 위해 많은 경우에 Controller를 썼습니다. 브라우저에서 접근할 때 다음과 같은 상황이 자주 발생합니다.
Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Fri Aug 04 17:49:02 HKT 2017
There was an unexpected error (type=Not Found, status=404).
No message available

사실 이것은 springmvc가 http 요청을 시작할 때 백그라운드에서 해당하는 RequestHandleMapping을 찾지 못했기 때문이다.springBoot은 기본적으로 잘못된 페이지를 되돌려주고 오류에 대한 기본 처리이다
2017-08-04 17:49:02.201 DEBUG org.springframework.web.servlet.DispatcherServlet Line:869 - DispatcherServlet with name 'dispatcherServlet' processing GET request for [/error]
2017-08-04 17:49:02.201 DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping Line:310 - Looking up handler method for path /error
2017-08-04 17:49:02.202 DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping Line:317 - Returning handler method [public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]
2017-08-04 17:49:02.202 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory Line:251 - Returning cached instance of singleton bean 'basicErrorController'
2017-08-04 17:49:02.202 DEBUG org.springframework.web.servlet.DispatcherServlet Line:955 - Last-Modified value for [/error] is: -1
2017-08-04 17:49:02.202 DEBUG org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor Line:85  - Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2017-08-04 17:49:02.204 DEBUG org.springframework.web.servlet.view.ContentNegotiatingViewResolver Line:263 - Requested media types are [text/html, text/html;q=0.8] based on Accept header types and producible media types [text/html])
2017-08-04 17:49:02.204 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory Line:251 - Returning cached instance of singleton bean 'error'

위의 로그에서 볼 수 있듯이 진정으로 작용하는 것은 BasicErrorController입니다.소스 코드를 보면 다음을 확인할 수 있습니다.
 @RequestMapping(
        produces = {"text/html"}
    )
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = this.getStatus(request);
        Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
        ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
        return modelAndView == null?new ModelAndView("error", model):modelAndView;
    }

springboot에서 기본적으로 지정한 반환 내용 형식은text/html이며, request 요청 헤더의 (Accept) 형식에 지정한 형식이 포함되어야 반환합니다.

사용자 정의 JSON 형식으로 데이터 반환


ErrorController 인터페이스를 사용하면
package com.minlia.cloud.exception.handler;

import com.minlia.cloud.body.StatefulBody;
import com.minlia.cloud.body.impl.FailureResponseBody;
import com.minlia.cloud.utils.EnvironmentUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ErrorAttributes;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 *  Rest 
 *
 * @author will
 * @author qianyi
 * @since 1.0
 */

@RestController
public class RestErrorEndpoint implements ErrorController {

    private static final String PATH = "/error";


    @Autowired
    private ErrorAttributes errorAttributes;

//    @RequestMapping(value = PATH)
    @RequestMapping(value = PATH,  produces = {MediaType.APPLICATION_JSON_VALUE})
    StatefulBody error(HttpServletRequest request, HttpServletResponse response) {
        if(!EnvironmentUtils.isProduction()) {
            return buildBody(request,true);
        }else{
            return buildBody(request,false);
        }
    }

    private StatefulBody buildBody(HttpServletRequest request,Boolean includeStackTrace){
        Map errorAttributes = getErrorAttributes(request, includeStackTrace);
        Integer status=(Integer)errorAttributes.get("status");
        String path=(String)errorAttributes.get("path");
        String messageFound=(String)errorAttributes.get("message");
        String message="";
        String trace ="";
        if(!StringUtils.isEmpty(path)){
            message=String.format("Requested path %s with result %s",path,messageFound);
        }
        if(includeStackTrace) {
             trace = (String) errorAttributes.get("trace");
             if(!StringUtils.isEmpty(trace)) {
                 message += String.format(" and trace %s", trace);
             }
        }
        return FailureResponseBody.builder().code(0).status(status).message(message).build();
    }

    @Override
    public String getErrorPath() {
        return PATH;
    }
    private Map getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
        RequestAttributes requestAttributes = new ServletRequestAttributes(request);
        return errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace);
    }
}

다시 요청하면 오류 페이지가 발생하지 않도록 되돌려줍니다.


{
    "timestamp":1501841693729,
    "requestId":"4bzKFSZ45gMyiAB9U808gDkplVM1RAJe20170804181453211403",
    "code":0,
    "status":404,
    "message":"Requested path /asfa with result Not Found"
}

좋은 웹페이지 즐겨찾기