提交 90ed0cf0 编写于 作者: B Brian Clozel

Document HTTP caching features in 4.2

Issue: SPR-11792
上级 7fa4ac1c
......@@ -1911,39 +1911,6 @@ which case they apply to matching controllers. This provides an alternative to u
`WebBindingInitializer`. See the <<mvc-ann-controller-advice>> section for more details.
[[mvc-ann-lastmodified]]
==== Support for the Last-Modified Response Header To Facilitate Content Caching
An `@RequestMapping` method may wish to support `'Last-Modified'` HTTP requests, as
defined in the contract for the Servlet API's `getLastModified` method, to facilitate
content caching. This involves calculating a lastModified `long` value for a given
request, comparing it against the `'If-Modified-Since'` request header value, and
potentially returning a response with status code 304 (Not Modified). An annotated
controller method can achieve that as follows:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@RequestMapping
public String myHandleMethod(WebRequest webRequest, Model model) {
long lastModified = // 1. application-specific calculation
if (request.checkNotModified(lastModified)) {
// 2. shortcut exit - no further processing necessary
return null;
}
// 3. or otherwise further request processing, actually preparing content
model.addAttribute(...);
return "myViewName";
}
----
There are two key elements to note: calling `request.checkNotModified(lastModified)` and
returning `null`. The former sets the response status to 304 before it returns `true`.
The latter, in combination with the former, causes Spring MVC to do no further
processing of the request.
[[mvc-ann-controller-advice]]
==== Advising controllers with the `@ControllerAdvice` annotation
The `@ControllerAdvice` annotation is a component annotation allowing implementation
......@@ -4029,6 +3996,7 @@ You do not need to define a `DefaultRequestToViewNameTranslator` bean explicitly
like the default settings of the `DefaultRequestToViewNameTranslator`, you can rely on
the Spring Web MVC `DispatcherServlet` to instantiate an instance of this class if one
is not explicitly configured.
====
Of course, if you need to change the default settings, then you do need to configure
......@@ -4038,9 +4006,16 @@ that can be configured.
[[mvc-caching]]
== HTTP caching support
A good HTTP caching strategy can significantly improve the performance of a web application
and the experience of its clients. The `'Cache-Control'` HTTP response header is mostly
responsible for this, along with conditional headers such as `'Last-Modified'` and `'ETag'`.
The `'Cache-Control'` HTTP response header advice private caches (e.g. browsers) and
public caches (e.g. proxies) on how they can cache HTTP responses for further reuse.
[[mvc-etag]]
== ETag support
An http://en.wikipedia.org/wiki/HTTP_ETag[ETag] (entity tag) is an HTTP response header
returned by an HTTP/1.1 compliant web server used to determine change in content at a
given URL. It can be considered to be the more sophisticated successor to the
......@@ -4048,6 +4023,163 @@ given URL. It can be considered to be the more sophisticated successor to the
client can use this header in subsequent GETs, in an `If-None-Match` header. If the
content has not changed, the server returns `304: Not Modified`.
This section describes the different choices available to configure HTTP caching in a
Spring Web MVC application.
[[mvc-caching-cachecontrol]]
=== Cache-Control HTTP header
Spring Web MVC supports many use cases and ways to configure "Cache-Control" headers for
an application. While the https://tools.ietf.org/html/rfc7234#section-5.2.2[RFC 7234 Section 5.2.2]
completely describes that header and its possible directives, there are several ways to
address the most common cases.
Spring Web MVC is using a configuration convention in several of its APIs:
`setCachePeriod(int seconds)`:
* A `-1` value won't generate a `'Cache-Control'` response header
* A `0` value will prevent caching using the `'Cache-Control: no-store'` directive
* A `n > 0` value will cache the given response for `n` seconds using the
`'Cache-Control: max-age=n'` directive
The {javadoc-baseurl}/org/springframework/http/CacheControl.html[`CacheControl`] builder
class simply describes the available "Cache-Control" directives and makes it easier to
build your own HTTP caching strategy. Once built, a `CacheControl` instance can be then
taken as an argument in several Spring Web MVC APIs.
[source,java,indent=0]
[subs="verbatim,quotes"]
----
// Cache for an hour - "Cache-Control: max-age=3600"
CacheControl ccCacheOneHour = CacheControl.maxAge(1, TimeUnit.HOURS);
// Prevent caching - "Cache-Control: no-store"
CacheControl ccNoStore = CacheControl.noStore();
// Cache for ten days in public and private caches,
// public caches should not transform the response
// "Cache-Control: max-age=864000, public, no-transform"
CacheControl ccCustom = CacheControl.maxAge(10, TimeUnit.DAYS)
.noTransform().cachePublic();
----
[[mvc-caching-static-resources]]
=== HTTP caching support for static resources
Static resources should be served with appropriate `'Cache-Control'` and conditional
headers for optimal performance.
<<mvc-config-static-resources,Configuring a `ResourceHttpRequestHandler`>> for serving
static resources not only natively writes `'Last-Modified'` headers by reading files
metadata, but also `'Cache-Control'` if properly configured.
You can set the `cachePeriod` attribute on a `ResourceHttpRequestHandler` or use
a `CacheControl` instance, which supports more specific directives:
[source,java,indent=0]
[subs="verbatim"]
----
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public-resources/")
.setCacheControl(CacheControl.maxAge(1, TimeUnit.HOURS).cachePublic());
}
}
----
And in XML:
[source,xml,indent=0]
[subs="verbatim"]
----
<mvc:resources mapping="/resources/**" location="/public-resources/">
<mvc:cachecontrol max-age="3600" cache-public="true"/>
</mvc:resources>
----
[[mvc-caching-etag-lastmodified]]
=== Support for the Cache-Control, ETag and Last-Modified response headers in Controllers
Controllers can support `'Cache-Control'` `'ETag'` and/or `'If-Modified-Since'` HTTP requests;
this is indeed recommended if a `'Cache-Control'` header is to be set on the response.
This involves calculating a lastModified `long` and/or an Etag value for a given request,
comparing it against the `'If-Modified-Since'` request header value, and potentially returning
a response with status code 304 (Not Modified).
As described in <<mvc-ann-httpentity>>, Controllers can access request/response using `HttpEntity` types.
Controllers returning `ResponseEntity` can include HTTP caching information in responses like this:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@RequestMapping("/book/{id}")
public ResponseEntity<Book> showBook(@PathVariable Long id) {
Book book = findBook(id);
String version = book.getVersion();
return ResponseEntity
.ok()
.cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
.eTag(version) // lastModified is also available
.body(book);
}
----
Doing this will not only include `'ETag'` and `'Cache-Control'` headers in the response, it will **also convert the
response to a `HTTP 304 Not Modified` response with an empty body** if the conditional headers sent by the client
match the caching information set by the Controller.
An `@RequestMapping` method may also wish to support the same behavior.
This can be achieved as follows:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@RequestMapping
public String myHandleMethod(WebRequest webRequest, Model model) {
long lastModified = // 1. application-specific calculation
if (request.checkNotModified(lastModified)) {
// 2. shortcut exit - no further processing necessary
return null;
}
// 3. or otherwise further request processing, actually preparing content
model.addAttribute(...);
return "myViewName";
}
----
There are two key elements here: calling `request.checkNotModified(lastModified)` and
returning `null`. The former sets the response status to 304 before it returns `true`.
The latter, in combination with the former, causes Spring MVC to do no further
processing of the request.
Note that there are 3 variants for this:
* `request.checkNotModified(lastModified)` compares lastModified with the
`'If-Modified-Since'` request header
* `request.checkNotModified(eTag)` compares eTag with the `'ETag'` request header
* `request.checkNotModified(eTag, lastModified)` does both, meaning that both
conditions should be valid for the server to issue an `HTTP 304 Not Modified` response
[[mvc-httpcaching-shallowetag]]
=== Shallow ETag support
Support for ETags is provided by the Servlet filter `ShallowEtagHeaderFilter`. It is a
plain Servlet Filter, and thus can be used in combination with any web framework. The
`ShallowEtagHeaderFilter` filter creates so-called shallow ETags (as opposed to deep
......@@ -4059,6 +4191,10 @@ compares the two hashes. If they are equal, a `304` is returned. This filter wil
save processing power, as the view is still rendered. The only thing it saves is
bandwidth, as the rendered response is not sent back over the wire.
Note that this strategy saves network bandwidth but not CPU, as the full response must be
computed for each request. Other strategies at the controller level (described above) can
save network bandwidth and avoid computation.
You configure the `ShallowEtagHeaderFilter` in `web.xml`:
[source,xml,indent=0]
......@@ -4075,6 +4211,24 @@ You configure the `ShallowEtagHeaderFilter` in `web.xml`:
</filter-mapping>
----
Or in Servlet 3.0+ environments,
[source,java,indent=0]
[subs="verbatim,quotes"]
----
public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {
// ...
@Override
protected Filter[] getServletFilters() {
return new Filter[] { new ShallowEtagHeaderFilter() };
}
}
----
See <<mvc-container-config>> for more details.
......@@ -4656,6 +4810,9 @@ And in XML:
<mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/>
----
For more details, see <<mvc-caching-static-resources, HTTP caching support for static resources>>.
The `mapping` attribute must be an Ant pattern that can be used by
`SimpleUrlHandlerMapping`, and the `location` attribute must specify one or more valid
resource directory locations. Multiple resource locations may be specified using a
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册