2016-08-21 2 views
-1

로케일 해결자를 위해 org.springframework.web.servlet.i18n.CookieLocaleResolver이있는 Spring Boot 응용 프로그램이 있습니다. !en과 같은 잘못된 언어 쿠키가있는 경우 java.lang.IllegalArgumentException: Locale part "!en" contains invalid characters 예외가 발생합니다.CookieLocaleResolver가있는 Spring Boot 응용 프로그램의 오류 페이지

이 예외는 Spring Boot에서 처리되지 않고 Servlet 컨테이너로 전달되는 문제입니다. 따라서 컨테이너의 기본 오류 페이지가 표시됩니다 (제 경우에는 JBoss EAP 6 임). 이는 스택 추적을 보여줍니다.

컨트롤러의 다른 예외는 올바르게 처리됩니다. 예를 들어, 제대로 처리되는 / by zero error을 던지는 컨트롤러 매핑이 있습니다.

다음과 같이 web.xml에서 오류 페이지 구성을 시도했습니다. 다음과

<error-page> 
    <location>/500</location> 
</error-page> 

는 MVC 컨트롤러 /error/500 모두 매핑.

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.autoconfigure.web.AbstractErrorController; 
import org.springframework.boot.autoconfigure.web.ErrorAttributes; 
import org.springframework.http.ResponseEntity; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 

import javax.servlet.http.HttpServletRequest; 

@Controller 
public class CustomErrorController extends AbstractErrorController { 
    public static final String ERROR_500 = "/500"; 
    private static final String ERROR_PATH= "/error"; 

    @Autowired 
    public CustomErrorController(ErrorAttributes errorAttributes) { 
     super(errorAttributes); 
    } 


    /** 
    * Responsible for handling all errors and throw especial exceptions 
    * for some HTTP status codes. Otherwise, it will return a map that 
    * ultimately will be converted to a json error. 
    */ 
    @RequestMapping({ERROR_PATH,ERROR_500}) 
    public ResponseEntity<?> handleErrors(HttpServletRequest request) { 
     return ResponseEntity.status(getStatus(request)).body(getErrorAttributes(request, false)); 
    } 

    @Override 
    public String getErrorPath() { 
     return ERROR_PATH; 
    } 
} 

그래도 컨테이너의 기본 오류 페이지가 표시됩니다. 이 문제를 해결하는 방법.

테스트 애플리케이션 코드는 요청을 처리 here

답변

1

FrameworkServlet, 로케일은 로케일 processDispatchResult에 걸려되지 않고 분해 할 때 발생 이러한 예외로 디스패처를 통해 요청을 전송하기 전에 결정 따라서 정상적인 WebMvc 오류처럼 처리되지 않습니다. 문맥의 경우 FrameworkServletDispatcherServlet에 의해 확장되고 buildLocaleContext(request)을 덮어 쓰고 차례로 CookieLocaleResolver을 호출합니다. buildLocaleContext에 대한

/** 
* Process this request, publishing an event regardless of the outcome. 
* <p>The actual event handling is performed by the abstract 
* {@link #doService} template method. 
*/ 
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) 
     throws ServletException, IOException { 

    long startTime = System.currentTimeMillis(); 
    Throwable failureCause = null; 

    // Here the locale is determined 
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); 
    LocaleContext localeContext = buildLocaleContext(request); 

    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); 
    ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); 

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); 
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); 

    initContextHolders(request, localeContext, requestAttributes); 

    try { 
     // here is where the WebMvc processing happens 
     doService(request, response); 
    } 
    catch (ServletException ex) { 
     failureCause = ex; 
     throw ex; 
    } 
    catch (IOException ex) { 
     failureCause = ex; 
     throw ex; 
    } 
    catch (Throwable ex) { 
     failureCause = ex; 
     throw new NestedServletException("Request processing failed", ex); 
    } 

    finally { 
     resetContextHolders(request, previousLocaleContext, previousAttributes); 
     if (requestAttributes != null) { 
      requestAttributes.requestCompleted(); 
     } 

     if (logger.isDebugEnabled()) { 
      if (failureCause != null) { 
       this.logger.debug("Could not complete request", failureCause); 
      } 
      else { 
       if (asyncManager.isConcurrentHandlingStarted()) { 
        logger.debug("Leaving response open for concurrent processing"); 
       } 
       else { 
        this.logger.debug("Successfully completed request"); 
       } 
      } 
     } 

     publishRequestHandledEvent(request, response, startTime, failureCause); 
    } 
} 

의 DispatcherServlet 방법()

/** 
* Build a LocaleContext for the given request, exposing the request's primary locale as current locale. 
* <p>The default implementation uses the dispatcher's LocaleResolver to obtain the current locale, 
* which might change during a request. 
* @param request current HTTP request 
* @return the corresponding LocaleContext 
*/ 
@Override 
protected LocaleContext buildLocaleContext(final HttpServletRequest request) { 
    if (this.localeResolver instanceof LocaleContextResolver) { 
     return ((LocaleContextResolver) this.localeResolver).resolveLocaleContext(request); 
    } 
    else { 
     return new LocaleContext() { 
      @Override 
      public Locale getLocale() { 
       return localeResolver.resolveLocale(request); 
      } 
     }; 
    } 
} 
+0

감사 숀, 지금은 디스패처 서블릿 매핑을 변경할 수 없습니다 나는이 곳의 많은의 코드를 변경해야합니다. Dispatcher 서블릿에서 web.xml에 구성된 오류 페이지를 제외시킬 수있는 방법이 있습니까? –

+0

성취하려는 내용이 확실하지 않습니다. 현지화 실패시에도 오류 페이지를 표시 하시겠습니까? 그렇다면 프로젝트에서 문제를 제기하여 정상적인 오류 처리가이 문제를 처리 할 수 ​​있도록 해당 측면을 향상시킬 수 있는지 확인하십시오. 또는 현지화 문자열에 문제가있는 경우 오류 페이지를 표시하지 않겠습니까? –

+0

문제점은 프레임 워크 서블릿에서 오류 페이지로 리다이렉트되었지만 프레임 워크 서블릿이'\ *'에 매핑되었을 때 오류 요청이 무한 루프 스프링 델리게이트를 피하기 위해 프레임 워크 서블릿을 통과 할 때 문제가 발생했습니다 컨테이너에의 에러. 오류 요청을 프레임 워크 서블릿에 매핑하지 않으려면이 요청을 제외시키는 방법이 필요합니다. –