-
Notifications
You must be signed in to change notification settings - Fork 38.5k
Add support for public/private Cache-Control HTTP header [SPR-7129] #11789
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Matthew Sgarlata commented To be super clear, if you don't put in public in your response headers, for applications running over HTTPS, then NO STATIC RESOURCES ARE CACHED EVER. They are downloaded every single time by every single browser, including modern ones like Chrome. If you are using a massive JS library like dojo that really sucks. |
marc schipperheyn commented This should be implemented in such a way that we have declarative control over this, based on requestmapping patterns |
marc schipperheyn commented I would recommend cacheMappings to work like so:
|
marc schipperheyn commented Ok, to be more in-line with the existing code:
The code to implement this seems trivial
|
Steven Willems commented Maybe it's worth looking at this implementation(by Scott Rossillo): https://github.com/foo4u/spring-mvc-cache-control/tree/master/spring-mvc-cache-control/src/main/java/net/rossillo/spring/web/mvc. |
marc schipperheyn commented I think I would prefer the declarative approach. It seems to provide more flexibility if the same code base is used for various sites and provides a central place to look for problems. But perhaps both are possible a declarative approach being superseded by a cacheheader annotation. |
marc schipperheyn commented Could we at the very least remove the "final" from cacheForSeconds so we can deal with this use case ourselves if it doesn't get picked up for the next release? Nothing more annoying than non overrideable methods. |
marc schipperheyn commented Slight addition value > 0: cache public x seconds |
marc schipperheyn commented I see that his has now been pushed to general backlog. I really think that not supporting private-cache headers is a major shortcoming of the framework, but regardless, could we at least remove the "final" from the relevant methods as a stopgap measure? |
Rossen Stoyanchev commented marc schipperheyn, thanks for bringing this up and suggesting a solution. I think the WebContentInterceptor change can be made independent of any declarative caching, which (when available) can act as an override. That said, in your solution, the public keyword is always applied (i.e. when cacheSeconds > 0). That would add the public keyword for everyone setting Cache-Control via WebContentInterceptor today and actually via all other sub-classes of WebContentGenerator, especially ResourceHttpRequestHandler. I'm not sure we can just do that. Here is a quote from Google's page speed project referenced above:
We may need to make this more configurable so applications can opt-in. In the very least a flag that enables adding either public or private. And then using the approach you suggested. The only other shortcoming I see is that there is no way to specify "cache private 1 seconds". What do you think? If you have any time at all to put together a pull request, we'll consider that right away. |
marc schipperheyn commented I can have a look at implementing this. You're right about the opt-in. Most important is that defaults don't change the current way it works. I'll have to look at header combinations to see what combinations are expected generally. |
Rossen Stoyanchev commented My understanding is the public directive allows caching by shared caches (e.g. proxies) whereas caching otherwise would only be done by non-shared caches (e.g. browsers). So there needs to be a way to request a Cache-Control header with all possible options: public, private, no-cache, or none. Looking at the approach of using cacheSeconds (negative vs positive), it wouldn't be possibly to request We'll probably need to introduce an overloaded method in WebContentGenerator, something like: protected final void checkAndPrepare(HttpServletRequest request, HttpServletResponse response,
int cacheSeconds, boolean lastModified, String cacheabilityDirective) {
} where the directive can be "public", "private", or null. In turn the WebContentInterceptor can have a similar property (hence one instance per directive) or it could accept cache mappings that look like this: /foo=11,private
/bar=22,public
/baz=33 |
marc schipperheyn commented The performance impact of this change can even be greater if one considers using cache-control private in combination with etags. It would allow you to cache dynamic pages in a static way without worrying about staleness. One has to consider security implications of course. In any case, this would suggest that the "must-revalidate" should be an optional part of the cache-control definition (both public and private) |
Mauro Molinari commented +1 for this. I'm not an expert on the subject, but after reading some documentation IMHO the use of "public/private" directives should be allowed independently of the "max-age". Also, although it's the most natural choice, why the "must-revalidate" header inclusion is forced on the response when cacheSeconds > 0 and the handler supports the LastModified interface? |
Scott Rossillo commented I wrote a project to manage Cache-Control headers on annotation based controllers and have successfully used it in multiple projects. This is my GitHub Project.
The project also contains a very simple working sample application. The implementation defines a type and method targetable Currently, the headers are written by a handler interceptor. I'd be happy to adjust this code as necessary and donate to Spring Source if you're interested.
|
Brian Clozel commented Given the current timetable, this issue has been rescheduled to 4.x backlog but will be addressed as a high priority for the next version. |
Rossen Stoyanchev commented Scott Rossillo, thanks for the reference to your project. In addition to this ticket there is also #13194 and we'll look to address both at the same time. |
marc schipperheyn commented I really hope that you guys will at least also implement the "configuration approach" as per some of the earlier comments as opposed to the "hardwire in Java" which looks better but is more limiting. The rationale for this is that a configuration style approach allows you to have different configurations based on a single platform (as is our case). E.g. a web page requires a logged in user (requires private) on one implementation but not on another (public suffices). |
Brian Clozel commented What do you mean by "configuration approach"? Is #13194 what you had in mind? |
marc schipperheyn commented No, in one of my earlier comments I talked about using a style such as used in the WebContentGenerator to express these kinds of configurations. This allows you to manage your settings without hardcoding them at the controller level such as #13194 suggests. |
Rossen Stoyanchev commented I agree interceptor-style should be preferred for configuring caching. The main reason for even considering I wonder if having an annotation isn't going too far. Perhaps we should change the scope for #13194 to be more along the lines of how we support not-modified with an etag in |
Brian Clozel commented Those changes will be available for WebContentGenerator. |
Christopher Smith commented As a note, the |
Brian Clozel commented A new Such a property can be configured like this for handling resources: @Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
CacheControl cc = CacheControl.maxAge(10, TimeUnit.DAYS)
.cachePublic();
registry.addResourceHandler("/resources/**")
.addResourceLocations("classpath:/resources/")
.setCacheControl(cc); See #16413 for more details. |
Zoran Regvart opened SPR-7129 and commented
As per The HTTP 1.1 RFC (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1) Cache-Control HTTP header can have keywords public or private specified.
One would use the public keyword for cacheable resources that are behind HTTP authentication -- a common case would be static javascript or image files that not accessible to general public. An even stronger case could be made for JSON/XML data intended for an AJAX client behind HTTP authentication that still wants to cache the response.
The private keyword is intended in cases where privacy of the cached data should be enforced -- for example for cached profile pages of the user.
These improvements would benefit applications that want comply with the recent trends in web site optimizations, such as the ones outlined in the best practices for caching section of Google's page speed project (http://code.google.com/speed/page-speed/docs/caching.html).
Affects: 3.0.2
This issue is a sub-task of #16413
Issue Links:
Referenced from: commits 38f32e3
11 votes, 23 watchers
The text was updated successfully, but these errors were encountered: