【问题标题】:spring boot error page with resource handlers带有资源处理程序的spring boot错误页面
【发布时间】:2016-08-24 15:44:35
【问题描述】:

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

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

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

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

我们的错误处理由以下人员完成:

  • 设置server.error.whitelabel.enabled=false
  • 子类化 Spring Boot 的默认 BasicErrorController 以覆盖 public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response)
  • 依靠我们已经配置的 thymeleaf 视图解析器来呈现我们的自定义错误页面

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

更新 1:

问题似乎与OncePerRequestFilter 和错误调度程序的组合有关。即:

  • ResouceUrlEncodingFilter 默认情况下不绑定到 ERROR 调度程序。虽然覆盖这很麻烦,但这并非不可能,但由于以下原因无济于事:
  • OncePerRequestFilterResourceUrlEncodingFilter 的父级)在请求上设置一个属性,指示它已被应用,以便不再重新应用。然后它包装响应对象。但是,当发送 ERROR 时,使用包装的响应,并且由于请求属性仍然存在,过滤器不会重新包装。

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

我觉得我一定错过了什么;在 Spring Boot 的 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;
    }
}

更好的解决方案?

【问题讨论】:

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


    【解决方案1】:

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

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

    谢谢!

    【讨论】:

    • 我的意思是。这应该是 2 中的第 1 步:确保这是一个错误,然后报告。只是忘记了“然后报告”...感谢您的链接。
    猜你喜欢
    • 2018-05-18
    • 1970-01-01
    • 2021-09-19
    • 2018-07-05
    • 2020-05-26
    • 1970-01-01
    • 2014-04-15
    • 2015-06-04
    • 2017-07-28
    相关资源
    最近更新 更多