@@ -1091,11 +1091,18 @@ configure the `ForwardedHeaderFilter` to remove and ignore such headers.
1091
1091
[[filters-shallow-etag]]
1092
1092
=== Shallow ETag
1093
1093
1094
- There is a `ShallowEtagHeaderFilter`. It is called shallow because it doesn't have any
1095
- knowledge of the content. Instead it relies on buffering actual content written to the
1096
- response and computing the ETag value at the end.
1094
+ The `ShallowEtagHeaderFilter` filter creates a "shallow" ETag by caching the content
1095
+ written to the response, and computing an MD5 hash from it. The next time a client sends,
1096
+ it does the same, but also compares the computed value against the `If-None-Match` request
1097
+ header and if the two are equal, it returns a 304 (NOT_MODIFIED).
1097
1098
1098
- See <<mvc-httpcaching-shallowetag>> for more details.
1099
+ This strategy saves network bandwidth but not CPU, as the full response must be computed
1100
+ for each request. Other strategies at the controller level, described above, can avoid the
1101
+ computation. See <<mvc-caching>>.
1102
+
1103
+ This filter has a `writeWeakETag` parameter that configures the filter to write Weak ETags,
1104
+ like this: `W/"02a2d595e6ed9a0b24f027f2b63b134d6"`, as defined in
1105
+ https://tools.ietf.org/html/rfc7232#section-2.3[RFC 7232 Section 2.3].
1099
1106
1100
1107
1101
1108
@@ -3736,46 +3743,33 @@ http://hdiv.org/[HDIV] is another web security framework that integrates with Sp
3736
3743
[[mvc-caching]]
3737
3744
== HTTP Caching
3738
3745
3739
- A good HTTP caching strategy can significantly improve the performance of a web application
3740
- and the experience of its clients. The `'Cache-Control'` HTTP response header is mostly
3741
- responsible for this, along with conditional headers such as `'Last-Modified'` and `'ETag'`.
3746
+ HTTP caching can significantly improve the performance of a web application. HTTP caching
3747
+ revolves around the "Cache-Control" response header and subsequently conditional request
3748
+ headers such as "Last-Modified" and "ETag". "Cache-Control" advises private (e.g. browser)
3749
+ and public (e.g. proxy) caches how to cache and re-use responses. An "ETag" header is used
3750
+ to make a conditional request that may result in a 304 (NOT_MODIFIED) without a body,
3751
+ if the content has not changed. "ETag" can be seen as a more sophisticated successor to
3752
+ the `Last-Modified` header.
3742
3753
3743
- The `'Cache-Control'` HTTP response header advises private caches (e.g. browsers) and
3744
- public caches (e.g. proxies) on how they can cache HTTP responses for further reuse.
3745
-
3746
- An http://en.wikipedia.org/wiki/HTTP_ETag[ETag] (entity tag) is an HTTP response header
3747
- returned by an HTTP/1.1 compliant web server used to determine change in content at a
3748
- given URL. It can be considered to be the more sophisticated successor to the
3749
- `Last-Modified` header. When a server returns a representation with an ETag header, the
3750
- client can use this header in subsequent GETs, in an `If-None-Match` header. If the
3751
- content has not changed, the server returns `304: Not Modified`.
3752
-
3753
- This section describes the different choices available to configure HTTP caching in a
3754
- Spring Web MVC application.
3754
+ This section describes HTTP caching related options available in Spring Web MVC.
3755
3755
3756
3756
3757
3757
3758
3758
[[mvc-caching-cachecontrol]]
3759
- === Cache-Control
3759
+ === `CacheControl`
3760
3760
3761
- Spring Web MVC supports many use cases and ways to configure "Cache-Control" headers for
3762
- an application. While https://tools.ietf.org/html/rfc7234#section-5.2.2[RFC 7234 Section 5.2.2]
3763
- completely describes that header and its possible directives, there are several ways to
3764
- address the most common cases.
3761
+ {api-spring-framework}/http/CacheControl.html[`CacheControl`] provides support for
3762
+ configuring settings related to the "Cache-Control" header and is accepted as an argument
3763
+ in a number of places:
3765
3764
3766
- Spring Web MVC uses a configuration convention in several of its APIs:
3767
- `setCachePeriod(int seconds)`:
3768
-
3769
- * A `-1` value won't generate a `'Cache-Control'` response header.
3770
- * A `0` value will prevent caching using the `'Cache-Control: no-store'` directive.
3771
- * An `n > 0` value will cache the given response for `n` seconds using the
3772
- `'Cache-Control: max-age=n'` directive.
3773
-
3774
- The {api-spring-framework}/http/CacheControl.html[`CacheControl`] builder
3775
- class simply describes the available "Cache-Control" directives and makes it easier to
3776
- build your own HTTP caching strategy. Once built, a `CacheControl` instance can then be
3777
- accepted as an argument in several Spring Web MVC APIs.
3765
+ * {api-spring-framework}/web/servlet/mvc/WebContentInterceptor.html[`WebContentInterceptor`]
3766
+ * {api-spring-framework}/web/servlet/support/WebContentGenerator.html[`WebContentGenerator`]
3767
+ * <<mvc-caching-etag-lastmodified>>
3768
+ * <<mvc-caching-static-resources>>
3778
3769
3770
+ While https://tools.ietf.org/html/rfc7234#section-5.2.2[RFC 7234] describes all possible
3771
+ directives for the "Cache-Control" response header, the `CacheControl` type takes a
3772
+ use case oriented approach focusing on the common scenarios:
3779
3773
3780
3774
[source,java,indent=0]
3781
3775
[subs="verbatim,quotes"]
@@ -3789,65 +3783,26 @@ accepted as an argument in several Spring Web MVC APIs.
3789
3783
// Cache for ten days in public and private caches,
3790
3784
// public caches should not transform the response
3791
3785
// "Cache-Control: max-age=864000, public, no-transform"
3792
- CacheControl ccCustom = CacheControl.maxAge(10, TimeUnit.DAYS)
3793
- .noTransform().cachePublic();
3786
+ CacheControl ccCustom = CacheControl.maxAge(10, TimeUnit.DAYS).noTransform().cachePublic();
3794
3787
----
3795
3788
3789
+ `WebContentGenerator` also accept a simpler `cachePeriod` property, in seconds, that
3790
+ works as follows:
3796
3791
3797
-
3798
- [[mvc-caching-static-resources]]
3799
- === Static resources
3800
-
3801
- Static resources should be served with appropriate `'Cache-Control'` and conditional
3802
- headers for optimal performance.
3803
- <<mvc-config-static-resources,Configuring a `ResourceHttpRequestHandler`>> for serving
3804
- static resources not only natively writes `'Last-Modified'` headers by reading a file's
3805
- metadata, but also `'Cache-Control'` headers if properly configured.
3806
-
3807
- You can set the `cachePeriod` attribute on a `ResourceHttpRequestHandler` or use
3808
- a `CacheControl` instance, which supports more specific directives:
3809
-
3810
- [source,java,indent=0]
3811
- [subs="verbatim"]
3812
- ----
3813
- @Configuration
3814
- @EnableWebMvc
3815
- public class WebConfig implements WebMvcConfigurer {
3816
-
3817
- @Override
3818
- public void addResourceHandlers(ResourceHandlerRegistry registry) {
3819
- registry.addResourceHandler("/resources/**")
3820
- .addResourceLocations("/public-resources/")
3821
- .setCacheControl(CacheControl.maxAge(1, TimeUnit.HOURS).cachePublic());
3822
- }
3823
-
3824
- }
3825
- ----
3826
-
3827
- And in XML:
3828
-
3829
- [source,xml,indent=0]
3830
- [subs="verbatim"]
3831
- ----
3832
- <mvc:resources mapping="/resources/**" location="/public-resources/">
3833
- <mvc:cache-control max-age="3600" cache-public="true"/>
3834
- </mvc:resources>
3835
- ----
3792
+ * A `-1` value won't generate a "Cache-Control" response header.
3793
+ * A `0` value will prevent caching using the `'Cache-Control: no-store'` directive.
3794
+ * An `n > 0` value will cache the given response for `n` seconds using the
3795
+ `'Cache-Control: max-age=n'` directive.
3836
3796
3837
3797
3838
3798
3839
3799
[[mvc-caching-etag-lastmodified]]
3840
- === @Controller caching
3841
-
3842
- Controllers can support `'Cache-Control'`, `'ETag'`, and/or `'If-Modified-Since'` HTTP requests;
3843
- this is indeed recommended if a `'Cache-Control'` header is to be set on the response.
3844
- This involves calculating a lastModified `long` and/or an Etag value for a given request,
3845
- comparing it against the `'If-Modified-Since'` request header value, and potentially returning
3846
- a response with status code 304 (Not Modified).
3800
+ === Controllers
3847
3801
3848
- As described in <<mvc-ann-httpentity>>, controllers can interact with the request/response using
3849
- `HttpEntity` types. Controllers returning `ResponseEntity` can include HTTP caching information
3850
- in responses like this:
3802
+ Controllers can add explicit support for HTTP caching. This is recommended since the
3803
+ lastModified or ETag value for a resource needs to be calculated before it can be compared
3804
+ against conditional request headers. A controller can add an ETag and "Cache-Control"
3805
+ settings to a `ResponseEntity`:
3851
3806
3852
3807
[source,java,indent=0]
3853
3808
[subs="verbatim,quotes"]
@@ -3859,79 +3814,60 @@ in responses like this:
3859
3814
String version = book.getVersion();
3860
3815
3861
3816
return ResponseEntity
3862
- .ok()
3863
- .cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
3864
- .eTag(version) // lastModified is also available
3865
- .body(book);
3817
+ .ok()
3818
+ .cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
3819
+ .eTag(version) // lastModified is also available
3820
+ .body(book);
3866
3821
}
3867
3822
----
3868
3823
3869
- Doing this will not only include `'ETag'` and `'Cache-Control'` headers in the response, it will **also convert the
3870
- response to an `HTTP 304 Not Modified` response with an empty body** if the conditional headers sent by the client
3871
- match the caching information set by the Controller .
3824
+ This will send an 304 (NOT_MODIFIED) response with an empty body, if the comparison
3825
+ to the conditional request headers indicates the content has not changed. Otherwise the
3826
+ "ETag" and "Cache-Control" headers will be added to the response .
3872
3827
3873
- An `@RequestMapping` method may also wish to support the same behavior.
3874
- This can be achieved as follows:
3828
+ The check against conditional request headers can also be made in the controller:
3875
3829
3876
3830
[source,java,indent=0]
3877
3831
[subs="verbatim,quotes"]
3878
3832
----
3879
3833
@RequestMapping
3880
3834
public String myHandleMethod(WebRequest webRequest, Model model) {
3881
3835
3882
- long lastModified = // 1. application-specific calculation
3836
+ long eTag = ... <1>
3883
3837
3884
- if (request.checkNotModified(lastModified)) {
3885
- // 2. shortcut exit - no further processing necessary
3886
- return null;
3838
+ if (request.checkNotModified(eTag)) {
3839
+ return null; <2>
3887
3840
}
3888
3841
3889
- // 3. or otherwise further request processing, actually preparing content
3890
- model.addAttribute(...);
3842
+ model.addAttribute(...); <3>
3891
3843
return "myViewName";
3892
3844
}
3893
3845
----
3894
3846
3895
- There are two key elements here: calling `request.checkNotModified(lastModified)` and
3896
- returning `null`. The former sets the appropriate response status and headers
3897
- before it returns `true`.
3898
- The latter, in combination with the former, causes Spring MVC to do no further
3899
- processing of the request.
3847
+ <1> Application-specific calculation.
3848
+ <2> Response has been set to 304 (NOT_MODIFIED), no further processing.
3849
+ <3> Continue with request processing.
3900
3850
3901
- Note that there are 3 variants for this:
3851
+ There are 3 variants for checking conditional requests against eTag values, lastModified
3852
+ values, or both. For conditional "GET" and "HEAD" requests, the response may be set to
3853
+ 304 (NOT_MODIFIED). For conditional "POST", "PUT", and "DELETE", the response would be set
3854
+ to 409 (PRECONDITION_FAILED) instead to prevent concurrent modification.
3902
3855
3903
- * `request.checkNotModified(lastModified)` compares lastModified with the
3904
- `'If-Modified-Since'` or `'If-Unmodified-Since'` request header
3905
- * `request.checkNotModified(eTag)` compares eTag with the `'If-None-Match'` request header
3906
- * `request.checkNotModified(eTag, lastModified)` does both, meaning that both
3907
- conditions should be valid
3908
3856
3909
- When receiving conditional `'GET'`/`'HEAD'` requests, `checkNotModified` will check
3910
- that the resource has not been modified and if so, it will result in a `HTTP 304 Not Modified`
3911
- response. In case of conditional `'POST'`/`'PUT'`/`'DELETE'` requests, `checkNotModified`
3912
- will check that the resource has not been modified and if it has been, it will result in a
3913
- `HTTP 409 Precondition Failed` response to prevent concurrent modifications.
3914
3857
3858
+ [[mvc-caching-static-resources]]
3859
+ === Static resources
3915
3860
3861
+ Static resources should be served with a "Cache-Control" and conditional response headers
3862
+ for optimal performance. See section on configuring <<mvc-config-static-resources>>.
3916
3863
3917
- [[mvc-httpcaching-shallowetag]]
3918
- === ETag Filter
3919
3864
3920
- Support for ETags is provided by the Servlet filter `ShallowEtagHeaderFilter`. It is a
3921
- plain Servlet Filter, and thus can be used in combination with any web framework. The
3922
- `ShallowEtagHeaderFilter` filter creates so-called shallow ETags by caching the content
3923
- written to the response and generating an MD5 hash over that to send as an ETag header.
3924
- The next time a client sends a request for the same resource, it uses that hash as the
3925
- `If-None-Match` value. The filter detects this, lets the request be processed as usual, and
3926
- at the end compares the two hashes. If they are equal, a `304` is returned.
3927
3865
3928
- Note that this strategy saves network bandwidth but not CPU, as the full response must be
3929
- computed for each request. Other strategies at the controller level, described above, can
3930
- avoid computation.
3866
+ [[mvc-httpcaching-shallowetag]]
3867
+ === ETag Filter
3931
3868
3932
- This filter has a `writeWeakETag` parameter that configures the filter to write Weak ETags,
3933
- like this: `W/"02a2d595e6ed9a0b24f027f2b63b134d6"`, as defined in
3934
- https://tools.ietf.org/html/rfc7232#section-2.3[RFC 7232 Section 2.3].
3869
+ The `ShallowEtagHeaderFilter` can be used to add "shallow" eTag values, computed from the
3870
+ response content and thus saving bandwith but not CPU time. See <<filters-shallow-etag>>.
3935
3871
3936
3872
3937
3873
0 commit comments