带资源处理程序的{spring}错误页面

时间:2016-08-24 15:44:36

标签: spring spring-mvc error-handling spring-boot static-resource

tl; dr:如何为Spring引导错误页面启用spring的ResourceUrlEncodingFilter?

(使用spring boot 1.3.7.RELEASE和Spring Framework / MVC 4.2.4.RELEASE时写的问题)

一些背景知识:我们有一个相当标准的spring boot / spring webmvc项目,使用Thymeleaf作为视图层。我们启用了开箱即用的弹簧启动资源链来提供静态资产。

我们的百万美元视图中包含标准的url编码语法,例如<script th:src="@{/js/some-page.js}"></script>。这依赖于Spring的org.springframework.web.servlet.resource.ResourceUrlEncodingFilter将网址转换为适当版本的网址,例如/v1.6/js/some-page.js

我们的错误处理是通过以下方式完成的:

  • 设置server.error.whitelabel.enabled=false
  • 继承Spring引导的默认BasicErrorController以覆盖public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response)
  • 依靠我们已配置的百万美元视图解析器来呈现我们的自定义错误页面

问题是:ResourceUrlEncodingFilter不适用于我们的错误页面。我认为缺少为ERROR调度请求注册的过滤器,但这对我来说并不明显:a)如何在spring boot中自定义;和b)为什么默认情况下没有这样做。

更新1:

问题似乎是OncePerRequestFilter和ERROR调度程序的组合。即:

    默认情况下,
  • ResouceUrlEncodingFilter不绑定到ERROR调度程序。虽然压倒这一点很麻烦,但并非不可能,但由于以下原因无法提供帮助:
  • OncePerRequestFilterResourceUrlEncodingFilter的父级)在请求中设置一个属性,指示已应用该属性以便不重新应用。然后它包装响应对象。但是,当调度ERROR时,包装的响应使用,并且由于请求属性仍然存在,过滤器不会重新换行。

更糟糕的是,自定义boolean hasAlreadyFilteredAttribute的逻辑不能被请求覆盖。 OncePerRequestFilter doFilter()方法 final getAlreadyFilteredAttributeName()(扩展点)无法访问当前请求对象以获取调度程序

我觉得我必须遗漏一些东西;在弹簧启动中,似乎无法在404页面上使用版本化资源。

更新2:一个工作但很混乱的解决方案

这是我能够提出的最好的,但仍然看起来非常混乱:

public abstract class OncePerErrorRequestFilter extends OncePerRequestFilter {

    @Override
    protected String getAlreadyFilteredAttributeName() {
        return super.getAlreadyFilteredAttributeName() + ".ERROR";
    }

    @Override
    protected boolean shouldNotFilterErrorDispatch() {
        return false;
    }

}

public class ErrorPageCapableResourceUrlEncodingFilter extends OncePerErrorRequestFilter {
    // everything in here is a perfect copy-paste of ResourceUrlEncodingFilter since the internal ResourceUrlEncodingResponseWrapper is private
}

// register the error-supporting version if the whitelabel error page has been disabled ... could/should use a dedicated property for this
@Configuration
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
@ConditionalOnClass(OncePerErrorRequestFilter.class)
@ConditionalOnWebApplication
@ConditionalOnEnabledResourceChain
@ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", havingValue="false", matchIfMissing = false)
public static class ThymeleafResourceUrlEncodingFilterErrorConfiguration {


    @Bean
    public FilterRegistrationBean errorPageResourceUrlEncodingFilterRegistration() {
        FilterRegistrationBean reg = new FilterRegistrationBean();
        reg.setFilter(new ErrorPageCapableResourceUrlEncodingFilter());
        reg.setDispatcherTypes(DispatcherType.ERROR);

        return reg;
    }
}

更好的解决方案?

1 个答案:

答案 0 :(得分:1)

这已在spring-projects/spring-boot#7348中报告,并且正在修复此问题。

您似乎已对该问题进行了广泛的分析;太糟糕了,你没有提前报告这个问题。下次,请考虑在Spring Boot跟踪器上提高它们。

谢谢!