I have strange discarding behavior of struts2 while setting cache option for my image.
I'm trying to put image from db to be cached on client side To render image I use ( http://struts.apache.org/2.x/docs/how-can-we-display-dynamic-or-static-images-that-can-be-provided-as-an-array-of-bytes.html ) where special result type render as follow:
public void execute(ActionInvocation invocation) throws Exception {
...//some preparation
HttpServletResponse response = ServletActionContext.getResponse();
HttpServletRequest request = ServletActionContext.getRequest();
ServletOutputStream os = response.getOutputStream();
try
{
byte[] imageBytes = action.getImage();
response.setContentType("image/gif");
response.setContentLength(imageBytes.length);
//I want cache up to 10 min
Date future = new Date(((new Date()).getTime() + 1000 * 10*60l));
;
response.addDateHeader("Expires", future.getTime());
response.setHeader("Cache-Control", "max-age=" + 10*60 + "");
response.addHeader("cache-Control", "public");
response.setHeader("ETag", request.getRequestURI());
os.write(imageBytes);
}
catch(Exception e)
{
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
os.flush();
os.close();
}
But when image is embedded to page it is always reloaded (Firebug shows code 200), and neither Expires, nor max-age are presented in header
Host localhost:9090
Accept image/png,image/*;q=0.8,*/*;q=0.5开发者_StackOverflow中文版
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300
Connection keep-alive
Referer http://localhost:9090/web/result?matchId=1
Cookie JSESSIONID=4156BEED69CAB0B84D950932AB9EA1AC;
If-None-Match /web/_srv/teamcolor
Cache-Control max-age=0
I have no idea why it is dissapered, may be problem in url? It is forms with parameter:
http://localhost:9090/web/_srv/teamcolor?loginId=3
At last I've discovered what wrong with my code, it is rather strange because it is partially works (image is displayed).
The culprit is following line:
HttpServletResponse response = ServletActionContext.getResponse();
It must be replaced with following:
HttpServletResponse response = (HttpServletResponse)
invocation.getInvocationContext().get(StrutsStatics.HTTP_RESPONSE);
It is looks like kind of magic, but obviously both response shares the same output stream but not the container of header declarations.
Not sure if this would work any better, but you could try. Create a custom interceptor that modifies the response headers. Something like this (note, I haven't tested this):
package com.yourpackage.interceptor;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.StrutsStatics;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class ResponseHeadersInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext context = invocation.getInvocationContext();
HttpServletResponse response = (HttpServletResponse)context.get(StrutsStatics.HTTP_RESPONSE);
HttpServletRequest request = (HttpServletRequest)context.get(StrutsStatics.HTTP_REQUEST);
if (response!=null) {
Date future = new Date(((new Date()).getTime() + 1000 * 10*60l));
response.addDateHeader("Expires", future.getTime());
response.setHeader("Cache-Control", "max-age=" + 10*60 + "");
response.addHeader("cache-Control", "public");
if (request!=null)
response.setHeader("ETag", request.getRequestURI());
}
return invocation.invoke();
}
}
Then in your struts.xml, define the interceptor and a new interceptor stack:
<interceptors>
<interceptor name="responseHeaders" class="com.yourpackage.interceptor.ResponseHeadersInterceptor" />
<interceptor-stack name="extendedStack">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="responseHeaders" />
</interceptor-stack>
</interceptors>
Then modify your action definition to use the extendedStack
.
精彩评论