Spring 4升级打破错误页面过滤器链

时间:2015-05-14 22:02:51

标签: spring-mvc

方案:
我们有一个拦截器,它在URL中查找伪造的属性,如果找到,则抛出NoSuchRequestHandlingMethodException。然后,我们会显示自定义的404页面。

所有页面都通过相同的过滤器链来设置本地请求状态,记录一些信息,然后显示请求的页面。在Spring 4中,在这种情况下,它停止了404页面的过滤器链。如果你进入一个完全虚假的页面,404工作,它仍然会通过它,但当我们抛出NoSuchRequestHandlingMethodException时,过滤器不会发生。

春天3:
 1.运行主要请求的过滤器链
 我们抛出NoSuchRequestHandlingMethodException
 3.过滤链条饰面
 4.新的过滤链启动
 5.我们记录错误页面指标
 6.我们向客户展示了一个很好的404页面

春天4:
 1.运行主要请求的过滤器链
 我们抛出NoSuchRequestHandlingMethodException
 3.过滤链条饰面
 4.我们尝试记录错误页面指标,但NPE因为第二个过滤器链从未开始  5.我们向客户显示一个可怕的空白页

在web.xml中过滤代码:

    <!-- The filter that captures the HttpServletRequest and HttpServletResponse--> 
     <filter>
      <filter-name>ServletObjectFilter</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
      <init-param>
          <param-name>targetBeanName</param-name>
          <param-value>xxxxxxx.servletObjectFilter</param-value>
      </init-param>
    </filter>
    <filter-mapping>
      <filter-name>ServletObjectFilter</filter-name>
      <servlet-name>springmvc</servlet-name>
      <dispatcher>REQUEST</dispatcher>
      <dispatcher>FORWARD</dispatcher>
      <dispatcher>ERROR</dispatcher>
    </filter-mapping>

...

    <error-page>
        <error-code>404</error-code>
        <location>/errors/404</location>
    </error-page>

过滤代码:

public void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain chain )
                throws ServletException, IOException {
    try {
        getServletContainer().setServletObjects( request, response );
        chain.doFilter( request, response );
    } finally {
        getServletContainer().removeAll();
    }

ServletContainer:

static final ThreadLocal< HttpServletRequest > REQUESTS = new ThreadLocal< HttpServletRequest >();
static final ThreadLocal< HttpServletResponse > RESPONSES = new ThreadLocal< HttpServletResponse >();

public void setServletObjects( HttpServletRequest request, HttpServletResponse response ) {
    REQUESTS.set( request );
    RESPONSES.set( response );
}

public void removeAll() {
    REQUESTS.remove();
    RESPONSES.remove();
}

然后失败的代码:

  public class RequestResponseAwareBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization( Object bean, String beanName ) {
       ...
       if ( bean instanceof RequestAware ) {
            HttpServletRequest request = getServletContainer().getRequest();
            if ( request == null ) {
                throw new IllegalStateException( "The request object is NULL" );
            }

            RequestAware requestAware = (RequestAware) bean;
            requestAware.setRequest( request );
        }
      }

1 个答案:

答案 0 :(得分:0)

我通过将我的错误页面@Controller拆分为两个来解决问题,其中一个是内部重定向的目标,没有得到过滤器链,而且它们是直接加载的,并且确实得到了过滤链。然后我将重定向@Controller添加到拦截器黑名单中,因此它不需要来自过滤器的任何逻辑或数据。它解决了这个特定的问题,但我担心我的代码库中的其他东西也依赖于这种行为。