Skip to content

Support Content-based Hash Fingerprinted URLs in ResourceHttpRequestHandler [SPR-10310] #14944

@spring-projects-issues

Description

@spring-projects-issues

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:

  1. 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 that ResourceHttpRequestHandler 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.)

  1. Add a "useCacheBusting" property to ResourceHttpRequestHandler (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:

  1. 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.

  2. 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:

Issue Links:

Referenced from: commits d4a0e62, 4ca7d89

6 votes, 12 watchers

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions