I'm using thymeleaf as template language for our error pages. Unfortunately when rendering links to our assets e.g. @{/css/toolkit.css}
the calculated hash which is appended is missing.
The bug can be reproduced using the example application at https://github.com/mvitz/spring-boot-exception-handling by doing these steps:
git clone https://github.com/mvitz/spring-boot-exception-handling
cd spring-boot-exception-handling
mvn spring-boot:run
When visiting localhost:8080/bar
the link looks like <link rel="stylesheet" href="/css/toolkit-90b322f81f9983dbd5ee8464f3e8b3db.css" />
on localhost:8080/foo
it looks like <link rel="stylesheet" href="/css/toolkit.css" />
Comment From: wilkinsona
This is an interesting one, and will probably require some of @bclozel's expertise.
There are a couple of problems. The first is that auto-configured ResourceUrlEncodingFilter
isn't called when the request is being dispatched to the error page. A workaround for this is to declare a registration bean that customises the dispatcher types:
@Bean
public FilterRegistrationBean resourceUrlEncodingFilterRegistration(ResourceUrlEncodingFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}
The second problem is that ResourceUrlEncodingFilter
is a OncePerRequestFilter
. This means that it wraps the response on the way into the controller, but is then skipped when the filter's called again on the way into the error page as it's all the same request.
I've opened SPR-14891 for the second problem. We can use this issue to tackle the first once we know the outcome of SPR-14891.
Comment From: bclozel
SPR-14891 is now fixed, and I've checked that this issue is fixed once the app: * depends on Spring Framework 4.3.5.BUILD-SNAPSHOT * depends on a local Spring Boot build which changes the automatic registration of the filter
Should we change all ResourceUrlEncodingFilter
registrations to use FilterRegistrationBean
s? Should we still apply @ConditionalOnMissingBean(ResourceUrlEncodingFilter.class)
on those bean methods or should we adapt the conditional to something else? It seems we're using a different set of conditions when registering the Jersey filter.
Comment From: wilkinsona
Jersey's complicated by the fact that we can use Jersey either as a Filter or as a Servlet. We can ignore that part of it. Its condition that looks for an existing filter registration with a specific name is interesting. I'd like to avoid that if possible as I don't like "magic" bean names.
I wonder if we need @ConditionalOnMissingFilter
? It could look for a bean of a particular type and, if it doesn't find one, look for a FilterRegistrationBean
that will register a Filter
of a particular type.
Comment From: bclozel
Agree, @ConditionalOnMissingFilter
should be a nice addition.
I've created #7475 and I'll tackle this one right after.
Comment From: michaelbull
Any update on this? A temporary workaround is to create a one-time filter that delegates to a ResourceUrlEncodingFilter
:
@Configuration
class ResourceConfiguration {
@Bean
fun resourceUrlEncodingFilter(): ResourceUrlEncodingFilter {
return ResourceUrlEncodingFilter()
}
@Bean
fun errorFilterBean(filter: ErrorResourceUrlEncodingFilter): FilterRegistrationBean<ErrorResourceUrlEncodingFilter> {
return FilterRegistrationBean<ErrorResourceUrlEncodingFilter>().apply {
this.filter = filter
setDispatcherTypes(DispatcherType.ERROR)
}
}
}
@Component
class ErrorResourceUrlEncodingFilter @Inject constructor(
private val resourceUrlEncodingFilter: ResourceUrlEncodingFilter
) : OncePerRequestFilter() {
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) = resourceUrlEncodingFilter.doFilter(request, response, filterChain)
override fun getAlreadyFilteredAttributeName(): String {
return super.getAlreadyFilteredAttributeName() + ".ERROR"
}
override fun shouldNotFilterErrorDispatch(): Boolean {
return false
}
}
Comment From: antoinelauzon-bell
Hi @bclozel,
Is this issue fixed? We still see this behavior (missing suffix for the assets referenced in the error.html page) in the latest Spring/Thymeleaf versions.
Work around proposed above (or below) works but I'm surprised it's required.
@Bean
public FilterRegistrationBean<ResourceUrlEncodingFilter> errorResourceUrlEncodingFilter() {
var filterRegistrationBean = new FilterRegistrationBean<>(new ResourceUrlEncodingFilter());
filterRegistrationBean.setDispatcherTypes(DispatcherType.ERROR);
return filterRegistrationBean;
}