Reputation: 2224
How to set Cache-control: private with applicationContext.xml in Spring 4.2 or later?
Cache-control:
HTTP headers can be set from applicationContext.xml
in Spring 4.1 like this:
<mvc:interceptors>
<bean id="webContentInterceptor"
class="org.springframework.web.servlet.mvc.WebContentInterceptor">
<property name="cacheSeconds" value="0"/>
<property name="useExpiresHeader" value="true"/>
<property name="useCacheControlHeader" value="true"/>
<property name="useCacheControlNoStore" value="true"/>
</bean>
</mvc:interceptors>
There are some annotation-based implementations like https://github.com/foo4u/spring-mvc-cache-control , but I prefer XML based configuration because I have to change HTTP headers according to testing/production environment (e.g. Chrome sends another request for "View page source" if the page returned with Cache-Control: private, no-store, no-cache, must-revalidate
, and make anti-CSRF tokens unmatch).
These settings are deprecated as of Spring 4.2.
Additionally, Cache-control: private
cannot be set from these settings. Because some CDN provider do not store contents if and only if http header contaings Cache-Control: private
, the support for this HTTP header is critical for the system that uses CDNs. e.g. http://tech.mercari.com/entry/2017/06/22/204500 or https://community.fastly.com/t/fastly-ttl/882 .
So I am looking for the way to set Cache-Control: private HTTP header from applicationContext.xml
for the sake of safety.
Upvotes: 1
Views: 2330
Reputation: 397
If you must use an XML config (like I had to), you can achieve it as follows -
Create CacheControl bean in XML by first calling a factory method that creates the bean for you. In your case you need an empty CacheControl to start with -
<bean id="cacheControlFactory" class="org.springframework.http.CacheControl" factory-method="empty" />
Now invoke the cachePrivate
method of the instance of CacheControl
with the help of org.springframework.beans.factory.config.MethodInvokingFactoryBean
-
<bean id="myCacheControl" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject">
<ref bean="cacheControlFactory"/>
</property>
<property name="targetMethod">
<value>cachePrivate</value>
</property>
</bean>
Now use the final bean holding your configuration, and invoke the addCacheMapping
method of webContentInterceptor
, and you're done. This config will apply to urls you send in as list in the varargs argument -
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject">
<ref bean="webContentInterceptor"/>
</property>
<property name="targetMethod">
<value>addCacheMapping</value>
</property>
<property name="arguments">
<list>
<ref bean="myCacheControl" />
<list>
<value>/home</value>
<value>/dp/**</value>
<value>/**/b/*</value>
</list>
</list>
</property>
</bean>
A working xml configuration can be found in this SO thread - How to set cacheControlMappings in WebContentInterceptor in Spring 5 Xml
Upvotes: 1
Reputation: 1096
It seems to be there is no XML out-of-the-box support in Spring 4.2+. As you can see here, there is no set
method for cacheControlMappings
of WebContentInterceptor
, so there is no chance to write values from XML configuration into it; and this map is intended to store url-cache-control mappings. However, CacheControl
class has public cachePrivate
method, that is possible to be used for registering custom configurations (I think that could be done with respect to dev or prod profiles); for example:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
CacheControl cacheControl = CacheControl.empty().cachePrivate();
registry.addResourceHandler("/**")
.setCacheControl(cacheControl);
}
Or directly in your controller (could be dependent on active profile too):
@RequestMapping(value = "/test")
public ResponseEntity<?> doHandleRequest () {
CacheControl cacheControl = CacheControl.empty().cachePrivate();
return ResponseEntity.ok()
.cacheControl(cacheControl);
}
If you certainly need to utilize XML configuration, nobody prevents you from writing custom subclass of WebContentInterceptor
with appropriate methods and logic, luckily, WebContentInterceptor
has addCacheMapping
method.
Upvotes: 2