Record what you learn and get straight to the subject.

Strong cache

Expires or cache-control
Expires: Wed, 22 Nov 2019 08:41:00 GMT
Copy the code

Expires is the expiration time, a field used by HTTP1.0; Tell the browser to fetch data directly from the cache before this time, without requesting it again. The resource will expire at 8:41 am on November 22, 2019. After the expiration date, the resource will be requested again.

The problem with this approach is that server time and client time can be inconsistent, resulting in cache clutter. This approach was therefore abandoned in HTTP/1.1

Cache-Control

In HTTP/1.1, a key field, cache-control, was adopted to Control the Cache by expiration time. The corresponding field is max-age. Take this example:

Cache-Control:max-age=3600
Copy the code

It uses expiration time to control the cache, meaning that the cache can be used directly within an hour,

It can actually combine a very large number of instructions and perform memory decisions for many more scenarios, listing some key attributes as follows:

  • Both public clients and proxy servers can cache;
  • Private only the browser can cache, intermediate proxy server can not cache
  • No-cache skips the current strong cache and sends an HTTP requestNegotiation cache phase
  • No-store is very crude and does no caching of any kind
  • S-maxage is similar to max-age except for the proxy server cache time

Note that cache-control takes precedence when both Expires and Cache-Control are present.

Of course, there is another case, when the resource cache time out, that is, the strong cache invalidates, so enter the second level of barrier — negotiated cache;

Negotiate the cache

Last-Modified

That is, the last modification time. This field is added to the response header the first time the browser sends a request to the server.

If the browser receives the request again, it will carry the if-modified-since field in the request header. The value of this field is the last-modified value returned by the server

If modified-since = If modified-since = If modified-since = If modified-since = If modified-since = If modified-since = If modified-since

  • If the value in the request header is less than the last modification time, it is time to update. Return the new resource, just like the normal HTTP request response flow.
  • Otherwise 304 is returned, telling the browser to use the cache directly
ETag

ETag is a unique identifier generated by the server based on the contents of the current file. This value changes whenever the file is changed. The server passes this value to the browser via the response header;

The browser receives the ETag value and sends it as if-none-match in the request header to the server on the next request.

The server receives if-none-match and compares it with ETag:

  • If they are the same, 304 is returned and the cache is used directly.
  • Otherwise, the description is updated. Return the new resource, just like the normal HTPP request response flow.
Both comparisons
  1. ETag is superior to Last-Modified in terms of accuracy. ETag marks resources according to the content, so it can accurately perceive the changes of resources. However, last-Modified cannot accurately perceive resource changes in some special cases, mainly in two cases:
  • Editing a file resource but not changing the file contents also invalidates the cache
  • Last-modified is sensed in seconds and cannot be sensed accurately if the change is less than 1 second.
  1. Last-modified is superior to ETag in performance. ETag generates hash values by removing the contents of a file every time it changes, while Last-Modified only records a point in time.

If last-Modified and ETag exist together, the server takes precedence over ETag.

The cache location

So we said, if the cache hits and we read resources directly from memory, where do we store those resources?

There are four types of cache locations in the browser, in descending order of priority:

  • Service Worker
  • Memory Cache
  • Disk Cache
  • Push Cache
Service Worker

Service Worker refers to the idea of Web Worker, that is, JS runs outside the main thread, because it is separated from the browser form, so it cannot access DOM directly. Even so, it can still help us complete many useful functions, such as: offline cache message push and network proxy and other functions; The offline Cache is the Service Worker Cache.

Memory Cache and Disk Cache

Memory Cache refers to the Memory Cache, which is the fastest in terms of efficiency. It is also shortest in terms of lifetime, and when the rendering process is finished, the memory cache is gone.

Disk Cache is the Cache on a Disk. The access efficiency is slower than memory because of the storage capacity and duration.

Since both have their advantages and disadvantages, how to choose the browser cache location?

  • Large JS CSS files are put into disk, otherwise put into memory
  • When the memory usage is high, files are preferentially transferred to disks
Push Cache

Push caching is the browser’s last line of defense. It is the content of HTTP/2, and will be used more and more widely as HTTP/2 becomes more popular. Please refer to the extension article on Push Cache

conclusion

So a quick summary of the browser Cache is that we use cache-control to verify that the strong Cache is hit. If it is hit, we use Cache directly, otherwise we enter the negotiated Cache and we use if-modified-since and if-none-match in the request header to determine whether it is hit

  • A 304 status code is returned telling the browser to read the resource from the cache
  • Otherwise, 200 status code is returned and the resource is updated.

practice

Build a little demo, project directory

index.html

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, <meta HTTP-equiv =" x-UA-compatible "content="ie=edge" /> <title> .image_box{ width: 800px; margin: 200px auto; } </style> <body> <div class="image_box"><img style="width: 100%;" src="./images/cat.jpeg" /></div> </body> </html>Copy the code

.babelrc

{
    "presets": [
        [
            "@babel/preset-env",
                {
                "targets": {
                    "node": "current"
                }
            }
        ]
    ]
}
Copy the code

index.js

require('@babel/register');
require('./server.js');
Copy the code

package.json

{" name ":" webcache ", "version" : "1.0.0", "description" : ""," main ":" index. Js ", "scripts" : {" server ": "nodemon ./index.js" }, "author": "webfansplz", "license": "MIT", "devDependencies": { "@babel/core": "^ 7.2.2 @", "Babel/preset - env" : "^ 7.2.3", "@ Babel/register" : "^ 7.0.0", "koa" : "^ 2.6.2", "koa - conditional - get" : "^ 3.0.0 koa", "- the etag" : "^ 4.0.0", "koa - static" : "^ 5.0.0"}, "dependencies" : {" koa - the router ":" ^ 10.1.1 ", "nodemon" : "^ 1.18.9}}"Copy the code

server.js

import Koa from 'koa'; import path from 'path'; Import resource from 'koa-static'; const app = new Koa(); import conditional from 'koa-conditional-get'; import etag from 'koa-etag'; const host = 'localhost'; const port = 3000; // etag works together with conditional-get // app.use(conditional()); // app.use(etag()); app.use(resource( path.join(__dirname, './static'), { // maxage: 10*1000 } )); app.listen(port, () => { console.log(`server is listen in ${host}:${port}`); });Copy the code

Next, the NPM Run Server starts

Browser localhost:3000 Open the page

Validation strong cache

The request to open the image we see,

Cache-Control:max-age=0
Copy the code

No caching by default, we set max-age to 10s and then request to release comments in server.js

maxage: 10*1000
Copy the code

Refresh the page,

Cache-control =10 cache-control =10 cache-control =10

The KOA-send library is introduced in the koA-static source code. The max-age of cahche-Control will be set as soon as maxage is passed.

And what we found is that

That is, every time the HTML strong cache is invalid,

You can see that the browser enforces cache-control :max-age=0 in the request header each time, presumably to ensure that the latest resource is retrieved each time.

Verify negotiation cache
  1. Last-Modified/If-Modified-Since

If you’ve noticed, the response header already contains the last-Modified field

When was last-Modified added? If you take the koA-Send source code,

If the last-Modified field is not present in the response header, add it. Note that this is for static resources only, and not all response headers have this field. For example, ajax requests do not have this field, as described below.

The Times in the request and response are the same. Why not hit the negotiation cache

app.use(conditional());
Copy the code

Let’s refresh the page again,

Return status code 304, matching the negotiation cache, then conditional() does what, intercepts the source code,

You can see the freshness of the request (described below) and return the 304 status code if freshness is available.

Change the picture secretly,

If the value of if-modified-since is less than the value of last-modified, you can see that the 200 OK status code has been rerequested.

  1. ETag/If-None-Match

How do I add the request, using the koa-etag module, release

app.use(etag());
Copy the code

And we eliminate last-modified,

The value of ETag is the same as the value of if-none-match, and the matching cache returns 304.

Next change the image and request again

If the value in ETag is different from that in if-none-match, request again. The logic is basically the same as last-modified/if-modified-since, with different conditions.

Freshness detection

  1. koa-conditional-get

Koa-conditional-get allows the cache to work, return 304,body null,

  1. In koa modulerequest.jssee

A status code of 200 to 300 and a freshness test of 304,

  1. Fresh main code
function fresh (reqHeaders, Var modifiedSince = reqHeaders['if-modified-since'] var var modifiedSince = reqHeaders['if-modified-since'] var var modifiedSince = reqHeaders['if-modified-since'] var NoneMatch = reqHeaders['if-none-match'] if (! modifiedSince && ! noneMatch) { return false } // 2. For end-to-end testing, because the browser cache-control: Var cacheControl = reqHeaders['cache-control'] if (cacheControl &&) Cache_control_no_cache_regexp. test(cacheControl)) {return false} // Compares ETag with if-none-match if (noneMatch && noneMatch ! == '*') { var etag = resHeaders['etag'] if (! etag) { return false } var etagStale = true var matches = parseTokenList(noneMatch) for (var i = 0; i < matches.length; i++) { var match = matches[i] if (match === etag || match === 'W/' + etag || 'W/' + match === etag) { etagStale = false Break}} if (etagStale) {return false}} // Compare ETag with if-modified-since if (modifiedSince) {var lastModified = resHeaders['last-modified'] var modifiedStale = ! lastModified || ! (parseHttpDate(lastModified) <= parseHttpDate(modifiedSince)) if (modifiedStale) { return false } } return true }Copy the code

Caching of Ajax requests

First of all, we should understand that ajax requests require us to manually set the response header cache-Control, last-Modified, and ETag, which should be defined according to the actual business scenario: For example, if max-age or Etag is generated, the browser will automatically carry the request headers for us, and Conditional will negotiate the cache control to return 304.

conclusion

  1. After the request is made, the cache is now looked up locally
  2. The request first validates the strong cacheCache-ControlHit or miss,max-ageIs late
  3. Expired re-request and cache to local, hit direct cache
  4. After the strong cache expires, the negotiation cache is enteredETagField consistent, consistent, return 304 using local cache
  5. Inconsistent, get data again and return 200
  6. There is noETagContrast,Last-ModifiedFields, andETagIn the same way.

For the front end, we can actually do very limited, because the response header about cache is mainly controlled by the back end, the browser will automatically carry the response header about the cache field, of course, we can also carry the cache related request header according to the actual situation, such as: no-cache, etc..

Refer to the article

  1. Easy to understand browser cache (Koa cache source code parsing)
  2. Practice this time to thoroughly understand the browser caching mechanism
  3. (1.6W word) browser soul ask, how many can you catch?