Designing Evolvable Web APIs with ASP.NET (2012)
Appendix D. Caching in Action
As we’ve seen, there are quite a few moving parts involved with HTTP caching. To illustrate how everything works together, let’s take a look at a common scenario involving two clients, an HTTP cache and the origin server. For the sake of brevity the body and all headers are not shown in the responses.
First, Client A does an initial request, as shown in Figure D-1.
Figure D-1. Client A does an initial GET
1. The cache receives the request, and seeing that it is a GET request checks whether it has a cached response. It doesn’t, so the cache forwards it on to the origin server.
2. The origin server generates a response, including ETag and max-age headers.
3. The cache receives the response and caches the result using a hash of the request URI and the Accept header value.
4. The cache then returns the response, including an additional AGE header to inform the client of the age of the representation.
5. Client A receives the representation and stores the ETag and Expires information.
Fifteen minutes later, Client B makes a request to the same resource, as shown in Figure D-2.
Figure D-2. Client B does an initial GET
1. The cache receives the request and checks whether it has a copy of the representation.
2. It sees from the matching on the URI and Accept that the representation is there and it is still fresh (based on the expiration), so it returns it immediately with the updated age.
3. Client B receives the representation and stores the ETag and Expires information.
An hour later, Client A does a conditional GET request back to the same resource, including the If-None-Match header, as shown in Figure D-3.
Figure D-3. Client A does a conditional GET
1. The cache receives the request and checks whether it has a copy of the representation. It finds the representation and sees that it is no longer fresh. It then forwards on the conditional GET request to the origin server to see if the copy it has is still valid.
2. The origin server receives the request and determines that the ETAG is still valid. It returns a 304 Not Modified with a new max-age.
3. The cache receives the request and returns the 304 to the client, along with an updated age calculation.
Time passes, and Client B does a conditional PUT against the contact resource, updating its state as shown in Figure D-4.
Figure D-4. Client B does a conditional PUT
1. The cache receives the request and seeing that it is a PUT, checks its cache to see if a copy exists for that resource, and if the ETag matches. Finding the copy, it invalidates the ETag for future requests. It then forwards on the request verbatim to the origin server.
2. The server applies the update and generates a new response with an updated ETag.
3. The cache receives the response and caches it. It then returns the response to Client B.
Client A comes along 10 minutes later and tries to also do a conditional PUT on the same resource as shown in Figure D-5.
Figure D-5. Client B does a conditional PUT
1. The cache receives its request and looks in its cache. It sees that it does not have a match on the ETag, as it was previously updated.
2. It returns a 409 Conflict to the client, informing it that the ETag it has is no longer valid.