Record the knowledge points (http://www.51testing.com/html/28/116228-238337.html)

Cache-Control Conditional GET request no-cache only-if-cached
Cache-Control: max-age=31536000, public The server returns last-Modified Not using caching Use caching only
Max-age indicates the validity period Request with: if-modified-since Error 503 / network error is returned if there is no match
The server returns: ETag
Request with if-none-match

Conditional GET request usage: server returns

Last-Modified: Sat, 4 Aug 2017 09:31:27 GMT
Copy the code

Please bring it again.

If-Modified-Since: Sat, 4 Aug 2017 09:31:27 GMT
Copy the code

The server decides that the cache is available and only returns 304


Server return

ETag: "1090c1ef-8603"
Copy the code

Please bring it again.

If-None-Match:"1090c1ef-8603"
Copy the code

The server decides that the cache is available and only returns 304


Remember the source code analysis of the interceptor chain last time? A complete interceptor chain is shown below

// Cache final InternalCache; public CacheInterceptor(InternalCache cache) { this.cache = cache; } @override public Response Intercept (Chain Chain) throws IOException {// Cache of this request Response cacheCandidate = cache! = null ? cache.get(chain.request()) : null; long now = System.currentTimeMillis(); // Cache policy. The most important thing is the get method inside. Like a decision tree, input requests and cached responses, CacheStrategy Strategy = new cacheStrategy.factory (now, chain-.Request (), cacheCandidate).get(); Request networkRequest = strategy.networkRequest; Response cacheResponse = strategy.cacheResponse;if(cache ! = null) { cache.trackResponse(strategy); }if(cacheCandidate ! = null && cacheResponse == null) { closeQuietly(cacheCandidate.body()); // The cache candidate wasn// Only cache and no cache hit, return 504 // If we're forbidden from using the network and the cache is insufficient, fail.
    if (networkRequest == null && cacheResponse == null) {
      return new Response.Builder()
          .request(chain.request())
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)") .body(Util.EMPTY_RESPONSE) .sentRequestAtMillis(-1L) .receivedResponseAtMillis(System.currentTimeMillis()) .build(); } // If we don't use cache't need the network, we're done.
    if (networkRequest == null) {
      returncacheResponse.newBuilder() .cacheResponse(stripBody(cacheResponse)) .build(); } // Continue down the interceptor chain and make a network request. try { networkResponse = chain.proceed(networkRequest); } finally { // If we're crashing on I/O or otherwise, don't leak the cache body.
      if(networkResponse == null && cacheCandidate ! = null) { closeQuietly(cacheCandidate.body()); // If we have a cache response too,then we're doing a conditional get. if (cacheResponse ! < span style = "box-sizing: border-box; color: RGB (74, 74, 74); If (networkResponse.code() == HTTP_NOT_MODIFIED) {Response Response = Cacheresponse.newBuilder () .headers(combine(cacheResponse.headers(), networkResponse.headers())) .sentRequestAtMillis(networkResponse.sentRequestAtMillis()) .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis()) .cacheResponse(stripBody(cacheResponse)) .networkResponse(stripBody(networkResponse)) .build(); networkResponse.body().close(); // Update the cache after combining headers but before stripping the // Content-Encoding header (as performed by initContentStream()). cache.trackConditionalCacheHit(); cache.update(cacheResponse, response); return response; } else { closeQuietly(cacheResponse.body()); } } Response response = networkResponse.newBuilder() .cacheResponse(stripBody(cacheResponse)) .networkResponse(stripBody(networkResponse)) .build(); // If (cache! = null) {/ / cache content and can cache (through the header, the remaining space, and so on) to determine if (HttpHeaders. HasBody (response) && CacheStrategy. IsCacheable (the response, NetworkRequest) {// Offer this request to the cache. Don't assume that just because you put it, you're caching it (for example, post requests are not cached). CacheRequest cacheRequest = cache.put(response); return cacheWritingResponse(cacheRequest, response); } / / the cache and then to judge the if (HttpMethod. InvalidatesCache (networkRequest. Method ())) {try {cache. Remove (networkRequest); } catch (IOException ignored) { // The cache cannot be written. } } } return response; }Copy the code

Next, look at the get method of the cache policy

public CacheStrategy get() {
      CacheStrategy candidate = getCandidate();

      if(candidate.networkRequest ! = null && request.cachecontrol ().onlyifcached ()) {// No cache hit and only cache used // We're forbidden from using the network and the cache is insufficient. return new CacheStrategy(null, null); } return candidate; } /** Returns a strategy to use assuming the request can use the network. */ private CacheStrategy getCandidate() { // // No cached response. If (cacheResponse == null) {return new CacheStrategy(request, null); } // Drop the cached response if it's missing a required handshake.
      if (request.isHttps() && cacheResponse.handshake() == null) {
        returnnew CacheStrategy(request, null); } // This request should not be cached... // If this response shouldn't have been stored, it should never be used // as a response source. This check should be redundant as long as the // persistence store is well-behaved and the rules are constant. if (! isCacheable(cacheResponse, request)) { return new CacheStrategy(request, null); } // No caching or header with eTag or if-modify-since CacheControl requestCaching = request.cachecontrol (); if (requestCaching.noCache() || hasConditions(request)) { return new CacheStrategy(request, null); } long ageMillis = cacheResponseAge(); long freshMillis = computeFreshnessLifetime(); if (requestCaching.maxAgeSeconds() ! = -1) { freshMillis = Math.min(freshMillis, SECONDS.toMillis(requestCaching.maxAgeSeconds())); } long minFreshMillis = 0; if (requestCaching.minFreshSeconds() ! = -1) { minFreshMillis = SECONDS.toMillis(requestCaching.minFreshSeconds()); } long maxStaleMillis = 0; CacheControl responseCaching = cacheResponse.cacheControl(); if (! responseCaching.mustRevalidate() && requestCaching.maxStaleSeconds() ! = -1) { maxStaleMillis = SECONDS.toMillis(requestCaching.maxStaleSeconds()); } if (! responseCaching.noCache() && ageMillis + minFreshMillis < freshMillis + maxStaleMillis) { Response.Builder builder = cacheResponse.newBuilder(); if (ageMillis + minFreshMillis >= freshMillis) { builder.addHeader("Warning", "110 HttpURLConnection \"Response is stale\""); } long oneDayMillis = 24 * 60 * 60 * 1000L; if (ageMillis > oneDayMillis && isFreshnessLifetimeHeuristic()) { builder.addHeader("Warning", "113 HttpURLConnection \"Heuristic expiration\""); } return new CacheStrategy(null, builder.build()); } // Check whether the cache has eTAG or lastModified, // Find a condition to add to the request. If the condition is satisfied, the response body // will not be transmitted. String conditionName; String conditionValue; if (etag ! = null) { conditionName = "If-None-Match"; conditionValue = etag; } else if (lastModified ! = null) { conditionName = "If-Modified-Since"; conditionValue = lastModifiedString; } else if (servedDate ! = null) { conditionName = "If-Modified-Since"; conditionValue = servedDateString; } else { return new CacheStrategy(request, null); // No condition! Make a regular request. } Headers.Builder conditionalRequestHeaders = request.headers().newBuilder(); Internal.instance.addLenient(conditionalRequestHeaders, conditionName, conditionValue); Request conditionalRequest = request.newBuilder() .headers(conditionalRequestHeaders.build()) .build(); return new CacheStrategy(conditionalRequest, cacheResponse); }Copy the code

The conclusion table is consistent with the above cache strategy

networkRequest cacheResponse result
null null Only -if-cached(503 error must be returned if no network request is made and the cache does not exist or is out of date)
null non-null No network requests are made, and the cache can be used, returning directly to the cache without requesting the network
non-null null If a network request is required and the cache does not exist or is out of date, or contains if-modified-since or if-none-match, access the network directly
non-null non-null The Header contains the ETag/ last-Modified tag, which needs to be used under conditional requests or requires access to the network

Conclusion table from author: BlackSwift end ———–