spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.22k stars 40.7k forks source link

Customize default resource handler #27179

Closed cdalexndr closed 3 years ago

cdalexndr commented 3 years ago

I want to use the default resource handler that is configured in spring.web.resources properties, but add my customization (add an unminify ResourceResolver). I'm using WebMvcConfigurer with addResourceHandlers( ResourceHandlerRegistry registry ).

Registering a resource handler using ResourceHandlerRegistry overwrites the default customization, so if I manually register the resource handler, I loose all the properties customization (compression, cache, etc.). The important class that customizes the resource handler by default is the private class ResourceChainResourceHandlerRegistrationCustomizer.

Currently there is no way to reuse this code. It would be nice to provide a method to customize the default behavior.

cdalexndr commented 3 years ago

Tried to move configuration from properties file to programmatic configuration, but now thymeleaf resource links do not contain version from content version strategy. This is because in ThymeleafAutoConfiguration, resourceUrlEncodingFilter has @ConditionalOnEnabledResourceChain that requires property configuration.

Workaround: copy-paste code to force create the ResourceUrlEncodingFilter bean. Downside is missing future updates from spring for this piece of code...

wilkinsona commented 3 years ago

Thanks for the suggestion. I wonder how practical it would be to allow customization of the default resource handler. For example, if you need to add a resolver in a particular position in the ResourceChainRegistration I don't think that's something that we could support with some changes in Framework. The same problem would affect ResourceChainResourceHandlerRegistrationCustomizer if we opened it up as well.

With that said, I'm not an expect on MVC's resource chain support. @bclozel and the rest of the team may have some better ideas.

bclozel commented 3 years ago

We've discussed this issue and I'm afraid we haven't found a proper solution for that.

From a Spring Framework perspective, the resource chain configuration should be centralized as the developer needs a complete view of the configured resolvers. Any error in the ordering can completely break the feature. Opening more the API on the Spring Framework side is hard; we can't think of a solution that wouldn't break with new resolvers or not make things significantly harder to understand.

From a Spring Boot perspective, we're helping developers with properties and conditions. To improve the situation, we'd need to open more this code and also look into Spring MVC beans to check whether the resource chain has been customized (this is not possible with our condition support).

Back to your main use case, this is the first time I'm hearing about unminifier being plugged in the resource chain. Usually, frontend developer tools can build dev-friendly versions or sourceMaps. I guess it's not possible with your current frontend stack.

I'm closing this issue as we don't think we can solve this problem and that taking full control of the resource chain and filter registration is the best course of action here.

Thanks!

cmrg-chb commented 9 months ago

I am in the same situation and would like to customize the default ResourceHttpRequestHandler . My use case is that I need to replace/overwrite the content-type of the delivered resource (x-gzip for a *.js.gz resource) with (encoding=gzip, content-type=application/javascript) due to a client that is very strict/stubborn (Unity WebGL player).

It would be very easy to do so, if I could replace the default handler, with a subclass that overrides getMimeType() and then provide the desired types based on the request path.

Unfortunately I cannot intercept the creation of ResourceHttpRequestHandler - if it were created with a factory or provider that is available as a bean, my problem would be solved (i.e. delegate creation of the handler in ResourceHandlerRegistration::getRequestHandeler to a customizable factory)

Using Spring Boot 3.x at the moment, it seems that the API has not really been opened much more in this respect. Does anybody know a work around?

cmrg-chb commented 9 months ago

PS: there is this solution to register a custom resource handler for a specific URL/path but as OP mentioned:

if I manually register the resource handler, I loose all the properties customization (compression, cache, etc.)