问题
In my Java / Struts2 / Tomcat application, when requesting some resources that generate a "304 Not Modified" response, the file is still being sent in the response.
This is a response example captured with Fiddler:
HTTP/1.1 304 Not Modified
Date: Thu, 26 Jun 2014 11:27:27 GMT
Server: Apache/2.2.16 (Ubuntu)
Connection: Keep-Alive
Keep-Alive: timeout=15, max=100
Vary: Accept-Encoding
/*! jQuery v1.7.2 jquery.com | jquery.org/license */
(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?
a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("
<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||
[...]
This is a problem because the content of the returned file is inserted into the next requested file, ending up in corruption and weird behavior.
This only happens on resources loaded from the "/struts" path, like:
/struts/utils.js
/struts/js/base/jquery-1.10.2.min.js
/struts/js/base/jquery.ui.core.min.js?s2j=3.7.0
The "/struts" path is handled by the struts2 class
org.apache.struts2.dispatcher.DefaultStaticContentLoader
These are the relevant elements of the system:
- Ubuntu 12.04.4 LTS (GNU/Linux 3.5.0-27-generic x86_64)
- JVM 1.6.0_31-b31 Sun Microsystems Inc. (also tried with ibm-java-x86_64-71)
- Apache2 2.2.22-1ubuntu1.6 with modjk
- Apache Tomcat/6.0.35
- Struts 2.3.16
- Sitemesh 3.0.0
When connecting directly to tomcat I don't get any unexpected data after the Not Modified header.
The Apache Server configuration hasn't been modified much, just an alias for /contents and two modjk directives:
JkMount /* ajp13_worker
JkUnMount /contents/* ajp13_worker
There is nothing related to /struts or caching or anything exotic. ModJK configuration is the default settings.
Any suggestion?
回答1:
This is an answer that doesn't solve the problem, but opens new questions.
The response corruption occurs when using sitemesh3 behind apache server. If I access the tomcat server directly, the response is a clean 304. If I access through a modjk/apache, the response contains unexpected data.
The reason for the unexpected data is due to how sitemesh works: when sending the response, at some point it forces struts to ignore any "If-Modified-Since" header, writing the requested content to the response buffer. It then goes on by adding the 304 headers as well at the beginning of the buffer.
See, for a start
org.sitemesh.webapp.contentfilter.HttpServletRequestFilterable
org.apache.struts2.dispatcher.DefaultStaticContentLoader.process()
I don't know where to go from here. Is it a bug? Is it an Apache Server bug or a Tomcat bug or a Struts bug or a Sitemesh bug?!
To replicate the problem, you need a tomcat behind apache running a struts webapp with sitemesh in it, and fetch this url twice while fiddler2 is active:
http://[test.server.address]/struts/utils.js
Piece of cake o_O'
Edit:
If I check the modjk log, I can clearly see the file transmitted back to Apache server:
: trying to connect socket 29 to 127.0.0.1:9009
: socket 29 [127.0.0.1:57195 -> 127.0.0.1:9009] connected
: sending to ajp13 pos=4 len=581 max=8192
.4.A....HTTP/1.1
.../struts/utils
.js...2.235.97.2
[...]
...Accept-Langua
ge..#en,en-US;q=
0.8,it-IT;q=0.6,
it;q=0.4....+JSE
SSIONID=B77369AB
D8239724A27A5CC5
6E06DED8...If-Mo
dified-Since...F
ri,.27.Jun.2014.
08:37:46.GMT....
.0....AJP_REMOTE
_PORT...19143...
.JK_LB_ACTIVATIO
N...............
: (rdp_worker) request body to send 0 - request body to resend 0
: received from ajp13 pos=0 len=20 max=8192
..0..Not.Modifie
d...............
: status = 304
: Number of headers is = 0
: received from ajp13 pos=0 len=4767 max=8192
.../*..*.$Id:.ut
ils.js.1240312.2
012-02-03.19:44:
51Z.jogep.$..*..
*.Licensed.to.th
e.Apache.Softwar
e.Foundation.(AS
F).under.one..*.
or.more.contribu
tor.license.agre
ements...See.the
[...]
the.ajaxValidati
on.interceptor.S
trutsUtils.getVa
lidationErrors.=
: ws_write::mod_jk.c (537): written 4763 out of 4763
: received from ajp13 pos=0 len=4 max=8192
................
: received from ajp13 pos=0 len=2 max=8192
................
: AJP13 protocol: Reuse is OK
When I access tomcat directly and dump the TCP traffic with tcpflow, I don't see any spurious data:
# tcpflow -p -s -c host xxx.xxx.xxx.xxx and port 8080
xxx.xxx.xxx.xxx.19292-yyy.yyy.yyy.yyy.08080: GET /rdp/struts/utils.js HTTP/1.1
Host: xxx.net:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en,en-US;q=0.8,it-IT;q=0.6,it;q=0.4
Cookie: JSESSIONID=B0F02CXXXEC3448F1B927C0E8C579A9B
If-Modified-Since: Fri, 27 Jun 2014 08:49:23 GMT
yyy.yyy.yyy.yyy.08080-xxx.xxx.xxx.xxx.19292: HTTP/1.1 304 Not Modified
Server: Apache-Coyote/1.1
Date: Fri, 27 Jun 2014 08:52:43 GMT
So there seems to be a different behavior in returning the buffer to an ajp port and returning it to a network socket. This is too low level for me to get any further.
Edit:
Workaround
The workaround I have implemented consists in letting Apache Server handle the /struts context:
- extract from the struts and struts-jquery-plugin jars all files that are affected (the content of org\apache\struts2\static and the content of template respectively)
- copy these files on a directory on the server
- create an alias in apache to serve that directory when the /struts path is encountered
- unmap the /struts path from modJK
来源:https://stackoverflow.com/questions/24430135/not-modified-header-followed-by-unexpected-content-body-with-sitemesh3-and-mod