📄 proxy-cache.xtp
字号:
<document> <header> <product>resin</product> <title>Server Caching</title> <description> <p>Server caching can speed dynamic pages to near-static speeds. When pages created by database queries only change every 15 minutes, e.g. CNN or Wikipedia or Slashdot, Resin can cache the results and serve them like static pages. Because Resin's caching only depends on HTTP headers, it will work for any JSPs, servlet or PHP page.response.</p> <p>Resin's caching operates like a proxy cache, looking at HTTP headers to compare hash codes or digests or simply caching for a static amount of time. Since the proxy cache follows the HTTP standards, applications like Mediawiki will automatically see dramatic performance improvement with no extra work. You can even cache REST-style GET requests.</p> <p>Because the cache supports advanced headers like "Vary", it can cache different versions of the page depending on the browser's capabilities. Gzip-enabled browsers will get the cached compressed page while more primitive browsers will see the plan page. With "Vary: Cookie", you can return a cached page for anonymous users, and still return a custom page for logged-in users.</p> </description> </header> <body> <localtoc/><s1 title="Overview"><p>For many applications, enabling the proxy cache canimprove your application's performance dramatically.When <a href="quercus.xtp">Quercus</a> runs Mediawiki with caching enabled,Resin can return results as fast as static pages. Without caching,the performance is significantly slower.</p><deftable title="Mediawiki Performance"><tr> <th>Cache Performance</th> <th>Non-Cache Performance</th></tr><tr> <td>4316 requests/sec</td> <td>29.80 requests/sec</td></tr></deftable><p>To enable caching, your application will need to set a few HTTP headers.While a simple application can just set a timed cache with <var>max-age</var>,a more sophisticated application can generate page hash digests with<var>ETag</var> and short-circuit repeated <var>If-None-Match</var>responses.</p><p>If subsections of your pages are cacheable but the main page is not,you can cache servlet includes just like caching top-level pages. Resin'sinclude processing will examine the headers set by your include servletand treat them just like a top-level cache.</p></s1><s1 title="HTTP Caching Headers"><deftable title="HTTP Server to Client Headers"><tr> <th width='40%'>Header</th> <th>Description</th></tr><tr> <td>Cache-Control: private</td> <td>Restricts caching to the browser only, forbidding proxy-caching.</td></tr><tr> <td>Cache-Control: max-age=<em>n</em></td> <td>Specifies a static cache time in seconds for both the browserand proxy cache.</td></tr><tr> <td>Cache-Control: s-maxage=<em>n</em></td> <td>Specifies a static cache time in seconds for the proxy cache only.</td></tr><tr> <td>Cache-Control: no-cache</td> <td>Disables caching entirely.</td></tr><tr> <td>ETag: <em>hash or identifier</em></td> <td>Unique identifier for the page's version. Hash-based values arebetter than date/versioning, especially in clustered configurations.</td></tr><tr> <td>Last-Modified: <em>time of modification</em></td> <td>Accepted by Resin's cache, but not recommended in clusteredconfigurations.</td></tr><tr> <td>Vary: <em>header-name</em></td> <td>Caches the client's header, e.g. Cookie, or Accept-encoding</td></tr></deftable><deftable title="HTTP Client to Server Headers"><tr> <th>Header</th> <th>Description</th></tr><tr> <td>If-None-Match</td> <td>Specifies the ETag value for the page</td></tr><tr> <td>If-Modified-Since</td> <td>Specifies the Last-Modified value for the page</td></tr></deftable><s2 title="Cache-Control: max-age"><p>Setting the <var>max-age</var> header will cache the resultsfor a specified time. For heavily loaded pages, even setting shortexpires times can significantly improve performance.Pages using sessions should set a "Vary: Cookie" header, so anonymous users will see the cached page, while logged-in userswill see their private page.</p><example title="Example: 15s cache"><%@ page session="false" %><%! int counter; %><%response.addHeader("Cache-Control", "max-age=15");%>Count: <%= counter++ %></example><p><var>max-age</var> is useful for database generated pages which arecontinuously, but slowly updated. To cache with a fixed content, i.e.something which has a valid hash value like a file, you canuse <var>ETag</var> with <var>If-None-Match</var>.</p></s2><s2 title="ETag and If-None-Match"><p>The <var>ETag</var> header specifies a hash or digest code for thegenerated page to further improve caching. The browser or cachewill send the <var>ETag</var> as a <var>If-None-Match</var> value when itchecks for any page updates. If the page is the same, the application willreturn a 304 NOT_MODIFIED response with an empty body. Resin's FileServletautomatically provides this capability for static pages. In general, theETag is the most effective caching technique, although it requires a bitmore work than <var>max-age</var>.</p><p>To handle clustered servers in a load-balanced configuration, thecalculated <var>ETag</var> should be a hash of the result value,not a timestamp or version. Since each server behind a load balancer willgenerate a different timestamp for the files, each server would producea different tag, even though the generated content was identical. So eitherproducing a hash or ensuring the <var>ETag</var> value is the same iscritical.</p><p><var>ETag</var> servlets will often also use <cache-mapping>configuration to set a <var>max-age</var> or <var>s-maxage</var>. Thebrowser and proxy cache will cache the page without revalidation until<var>max-age</var> runs out. When the time expires, it will use<var>If-None-Match</var> to revalidate the page.</p><p>When using <var>ETag</var>, your application will need to look for the<var>If-None-Match</var> header on incoming requests. If the value is thesame, your servlet can return 304 NOT-MODIFIED. If the value differs,you'll return the new content and hash.</p><example title="Example: ETag servlet">import java.io.*;import javax.servlet.*;import javax.servlet.http.*;public class MyServlet extends HttpServlet{ public void doGet(HttpServletRequest req, HttpServletResponse res) { String etag = getCurrentEtag(); String ifNoneMatch = req.getHeader("If-None-Match"); if (ifNoneMatch != null && ifNoneMatch.equals(etag)) { res.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return; } res.setHeader("ETag", etag); ... // generate response }}</example><example title="Example: HTTP headers for ETag match">C: GET /test-servlet HTTP/1.1S: HTTP/1.1 200 OKS: ETag: xm8vz29IS: Cache-Control: max-age=15sS: ...C: GET /test-servlet HTTP/1.1C: If-None-Match: xm8vz29IS: HTTP/1.1 304 Not ModifiedS: Cache-Control: max-age=15sS: ...</example><example title="Example: HTTP headers for ETag mismatch">C: GET /test-servlet HTTP/1.1C: If-None-Match: UXi456WwS: HTTP/1.1 200 OKS: ETag: xM81x+3jS: Cache-Control: max-age=15sS: ...</example></s2><s2 title="Expires"><p>Although max-age tends to be easier and more flexible, an applicationcan also set the <var>Expires</var> header to enable caching, when theexpiration date is a specific time instead of an interval.For heavily loaded pages, even setting shortexpires times can significantly improve performance. Sessions shouldbe disabled for caching.</p><p>The following example sets expiration for 15 seconds. So thecounter should update slowly.</p><example title="Example: expires"><%@ page session="false" %><%! int counter; %><%long now = System.currentTimeMillis();response.setDateHeader("Expires", now + 15000);%>Count: <%= counter++ %></example><p><var>Expires</var> is useful for database generated pages which arecontinuously, but slowly updated. To cache with a fixed content, i.e.something which has a valid hash value like a file, you canuse <var>ETag</var> with <var>If-None-Match</var>.</p></s2><s2 title="If-Modified-Since"><p>The <var>If-Modified-Since</var> headers let you cache based on anunderlying change date. For example, the page may only change when anunderlying source page changes. Resin lets you easily use <var>If-Modified</var> by overriding methods in HttpServlet orin a JSP page.</p><p>Because of the clustering issues mentioned in the ETag section, it'sgenerally recommended to use ETag and If-None-Match and avoidIf-Modified-Since. In a load balanced environment, each backend serverwould generally have a different Last-Modified value, while would effectivelydisable caching for a proxy cache or a browser that switched from onebackend server to another.</p><p>The following page only changes when the underlying 'test.xml'page changes.</p><example><%@ page session="false" %><%!int counter;public long getLastModified(HttpServletRequest req){ String path = req.getRealPath("test.xml"); return new File(path).lastModified();}%>Count: <%= counter++ %></example><p><var>If-Modified</var> pages are useful in combination with the<var>cache-mapping</var> configuration.</p></s2><s2 title="Vary"><p>In some cases, you'll want to have separate cached pages for the same URLdepending on the capabilities of the browser. Using gzip compression isthe most important example. Browsers which can understandgzip-compressed files receive the compressed page while simple browserswill see the uncompressed page. Using the "Vary" header, Resin cancache different versions of that page.</p><example title="Example: vary caching for on gzip"><% response.addHeader("Cache-Control", "max-age=3600"); response.addHeader("Vary", "Accept-Encoding");%>Accept-Encoding: <%= request.getHeader("Accept-Encoding") %></example><p>The "Vary" header can be particularly useful for caching anonymouspages, i.e. using "Vary: Cookie". Logged-in users will get their custompages, while anonymous users will see the cached page.</p></s2></s1>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -