2016-08-21 171 views
-1

我有一个Spring Boot应用程序,其中包含用于区域设置解析器的org.springframework.web.servlet.i18n.CookieLocaleResolver。如果有像!en这样的无效语言cookie,那么将会有一个例外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> 

并映射二者/error/500到MVC控制器如下。

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实例。

/** 
* 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); 
    } 
} 

为buildLocaleContext 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

感谢肖恩,现在我不能改变映射到调度的servlet然后我不得不改变在很多地方的代码。有什么方法可以从调度程序servlet中排除在web.xml中配置的错误页面。 –

+0

不知道你正在努力完成什么。如果出现本地化故障,您是否还想要显示错误页面?如果是这样的话,我会在项目中提出一个问题,看看他们是否可以增强该方面,以允许正常的错误处理来处理这种情况。 或者你想不显示错误页面,如果有本地化字符串问题? –

+0

问题是当框架servlet中有一个异常时,它被重定向到错误页面,但框架servlet被映射到'\ *'错误请求也会通过框架servlet,因为这样可以避免无限循环spring委托容器的错误。我不希望将错误请求映射到框架servlet是否有排除它的方法。 –

相关问题