【问题标题】:Spring 4 upgrade broke error page filter chainSpring 4 升级破坏了错误页面过滤器链
【发布时间】:2015-05-14 22:02:50
【问题描述】:

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

所有页面都经过同一个过滤器链来设置本地请求状态,记录一些信息,然后显示请求的页面。在 Spring 4 中,在这种情况下,它停止通过 404 页面的过滤器链。如果您转到一个完全伪造的页面,它仍然会通过它,并且 404 有效,但是当我们抛出 NoSuchRequestHandlingMethodException 时,过滤器不会发生。

春季 3:
1. 运行主请求的过滤器链
2.我们抛出NoSuchRequestHandlingMethodException
3.过滤链完成
4. 新的过滤器链启动
5. 我们记录错误页面指标
6.我们向客户展示一个漂亮的404页面

春季 4:
1. 运行主请求的过滤器链
2.我们抛出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 );
        }
      }

【问题讨论】:

  • 您的问题令人困惑。你在使用过滤器还是拦截器?只有一个过滤器链,因此您不会开始新的过滤器链(除非您自己破解某些东西?)。发布一些代码,因为您现在只有 web.xml 的一部分。
  • 我们同时使用过滤器和拦截器。我们使用过滤器将我们需要的状态注入 Spring,然后我们在拦截器中使用该状态。也许我们自己正在破解一些停止使用 Spring 4 的东西。不幸的是,web.xml 超过 300 行。
  • 希望我添加了更多有用的代码。我添加了在 Spring 3 上运行两次的过滤器,在 Spring 4 上只运行一次,以及在 Spring 4 上初始化我们的拦截器失败的 BeanPostProcessor,因为它假定过滤器已经运行。

标签: spring-mvc


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-11
    • 1970-01-01
    • 1970-01-01
    • 2015-07-22
    • 1970-01-01
    • 1970-01-01
    • 2018-11-04
    • 2012-07-27
    相关资源
    最近更新 更多