-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Description
Kent Rancourt opened SPR-10310 and commented
ResourceHttpRequestHandler
's configurable "cacheSeconds
" property is a great performance feature that allows the setting of a far-future expiry date on the static resources it serves. Of course, the downside to this is that if static resources are modified in a subsequent release, browsers that already have them cached won't request new versions for a long time and therefore wind up utilizing stale resources.
To circumvent this, a "cache-busting" strategy is called for in order to "trick" browsers into making a new request by supplying them with a different URL to follow. The Spring reference documentation (chapter 17) offers up one possible strategy for accomplishing this, but with this being a common concern, should support not be built directly into Spring MVC?
I have been inspired by how the Ruby on Rails "asset pipeline" accomplishes cache-busting, so if I may be so bold as to suggest an implementation, something like the following might work nicely:
- Provide a series of custom JSP tags like
<resource:image/css/javascript>
. If cache-busting is enabled, these tags will seek out the indicated resource (by looking in the same locations thatResourceHttpRequestHandler
is configured to serve resources from). Upon finding the resource, it will calculate an MD5 checksum of that resource and incorporate that fingerprint into the URL that it outputs into the src or href attribute of whatever HTML element the tag is producing.
By way of example, <asset:image src="/images/logo.png"/>
might produce <img src="/<context-root>/resources/images/logo-<md5sum>.png"/>
(Also, a simple Map can be used internally to cache calculated checksums to improve the performance of this algorithm on subsequent executions.)
- Add a "
useCacheBusting
" property toResourceHttpRequestHandler
(and the<mvc:resources>
tag in the Spring MVC config namespace). Enhance this class to detect and strip the MD5 checksum suffix from the URL before looking for the requested resource. (There is no need to even DO anything with the MD5 checksum. It was only there to trick the browser into make a new request.)
Developers using this enhancement would need to do no more than enable it using the namespace and use the <resource:image/css/javascript>
JSP tags.
The strategy, apart from being quite seamless, is also wholly compatible with additional strategies that might be used to accelerate the serving of static resources. For instance, if a develop wishes to short-circuit requests for static resource by serving them from the web server, there are two options that are fully compatible with the cache-busting strategy outlined here:
-
Use a Maven build plugin to suffix static resource filenames with MD5 checksums. Whatever deploy process copies the static resources to the web server will then be copying resources with the exact names that the new JSP tags will be directing the browser to request.
-
If the developer has control of the web server and doesn't like Spring core JMS pom.xml #1, they can also consider using web server rewrite rules to drop the MD5 checksum from the resource URL before looking for the resource to serve up.
In any event, having the cache-busting strategy built into the framework would probably encourage more developers to use far-future expiration dates- which are GREAT for performance, but difficult to work with in the absence of a solid cache-busting strategy.
Affects: 3.2.1
Sub-tasks:
- Add setJavaScriptModuleLoaderMode (or similar) property to FingerprintResourceResolver [SPR-11865] #16484 Add setJavaScriptModuleLoaderMode (or similar) property to FingerprintResourceResolver
Issue Links:
- Enhance ResourceHttpRequestHandler with ResourceResolver strategy [SPR-10933] #15561 Enhance ResourceHttpRequestHandler with ResourceResolver strategy ("depends on")
- Enhance ResourceHttpRequestHandler with ResourceTransformer strategy [SPR-11800] #16420 Enhance ResourceHttpRequestHandler with ResourceTransformer strategy ("depends on")
Referenced from: commits d4a0e62, 4ca7d89
6 votes, 12 watchers