I'm serving up images from my servlet. The response content type is image/jpeg. I find that images requested from my servlet are not cached. How do I get them to be cached like file image requests normally are? I tried setting Cache-Control: public but to no avail.
问题:
回答1:
The default servlet serving static content in containers like Tomcat doesn't set any cache control headers. You don't need write a servlet just for that. Just create a filter like this,
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
long expiry = new Date().getTime() + cacheAge*1000;
HttpServletResponse httpResponse = (HttpServletResponse)response;
httpResponse.setDateHeader("Expires", expiry);
httpResponse.setHeader("Cache-Control", "max-age="+ cacheAge);
chain.doFilter(request, response);
}
Whenever you want add cache control, just add the filter to the resources in web.xml. For example,
<filter>
<filter-name>CacheControl</filter-name>
<filter-class>filters.CacheControlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CacheControl</filter-name>
<url-pattern>/images/*</url-pattern>
</filter-mapping>
回答2:
You need to send the ETag
, Last-Modified
and Expires
headers along the response. The ETag
represents the unique identifier of the file (usually composed based on a combination of filename, filesize and lastmodified timestamp). The Last-Modified
represents the last modified timestamp of the file. The Expires
header denotes how long the client is allowed to keep the file in cache. If the cache has been expired and the ETag
or Last-Modified
are available, then the client will send a HEAD
request to check if the file needs to be renewed. If not, then the Expires
will just be postponed again accordingly.
You can find here a servlet example which handles this all (and download resumes and automatic GZIP): FileServlet supporting resume and GZIP
回答3:
For example, if you want to cache them for 1 month:
Calendar inOneMonth = Calendar.getInstance();
inOneMonth.add(Calendar.MONTH, 1);
response.setDateHeader("Expires", inOneMonth.getTimeInMillis());
(this is in a Filter
that handles the *.jpg
pattern, for example)
But images should be cached by default - check your filters and configurations to see if something isn't setting the cache parameters incorrectly.
回答4:
Ok.. looks like the default header fields should enable caching. I found a solution in another forum. Apparently, you need to explicitly set a content-length in the response. Wonder why though. I thought the HttpServletResponse would do that for us. Anyway, it worked like a charm and the image is getting cached nicely.