springspring-mvcerror-handlingspring-bootstatic-resource

spring boot error page with resource handlers


tl;dr: how to enable spring's ResourceUrlEncodingFilter for spring boot Error pages?

(Question written while using spring boot 1.3.7.RELEASE and Spring Framework/MVC 4.2.4.RELEASE)

Some background: We have a fairly standard spring boot/spring webmvc project using Thymeleaf as the view layer. We have the out-of-the-box spring boot Resource Chain enabled to serve static assets.

Our thymeleaf views have standard url-encoding syntax in them such as <script th:src="@{/js/some-page.js}"></script>. This relies on Spring's org.springframework.web.servlet.resource.ResourceUrlEncodingFilter to transform the url into an appropriately-versioned url such as /v1.6/js/some-page.js.

Our error handling is done by:

The problem is: the ResourceUrlEncodingFilter isn't applying on our error pages. I assume it's a lack of the filter being registered for ERROR dispatched requests, but it's not obvious to me: a) how to customize this in spring boot; and b) why this wasn't done by default.

Update 1:

The issue seems to be with a combination of OncePerRequestFilter and the ERROR dispatcher. Namely:

Worse still, the logic for customizing boolean hasAlreadyFilteredAttribute is not overridable by request. OncePerRequestFilter's doFilter() method is final, and getAlreadyFilteredAttributeName() (the extension point) does not have access to the current request object to get the dispatcher.

I feel like I must be missing something; it seems impossible to use versioned resources on a 404 page in spring boot.

Update 2: A working but messy solution

This is the best I've been able to come up with, which still seems awfully messy:

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;
    }
}

Better solutions?


Solution

  • This has been reported in spring-projects/spring-boot#7348 and a fix is on its way.

    It seems you've made an extensive analysis of the issue; too bad you didn't report this issue earlier. Next time, please consider raising those on the Spring Boot tracker.

    Thanks!