“Learned and forgotten.” If you leave a piece of knowledge unread for too long, the genetic fragment in your mind will become blurred, but the genetic index is still there. This article tries to help you memorize common knowledge points more deeply by combining practical theory. If there are any deficiencies, please correct them.

What is HTTP caching?

HTTP caching in plain English: when a client requests a resource from the server, it does not fetch the resource directly from the server (hello: server, give me the latest selfie picture). Instead, check to see if there are any resources in your storage that are still valid from the last time you saved them. If so, you save a lot of freight. Here’s a simple example:

  • Client needsa.jsA request header is sent(1kb)
  • Returns after the server respondsa.js(10kb)+ response headers(1kb)
  • And over and over again11kbTraffic transmission

However, the content of the file A.js that we need often does not change, but still needs to waste traffic. In order to solve this problem, people put forward the concept of HTTP cache.

HTTP caching can be divided into strong caching and negotiated caching.

Strong cache

  • Expires
  • Cache-Control
  • Pragma

Negotiate the cache

  • Last-Modified
  • If-Modified-Since
  • ETag
  • If-Not-Match

Strong cache vs. negotiated cache:

User: I need A.js now, please help me get the strong cache: wait a minute, LET me check if I have a backup of A.js, here it is. Negotiation cache: I also have a backup here, but I have to ask the server if this backup is the latest model, send request headers (1KB traffic). The server reply (1KB traffic) header uses local backup, and the latest data returned by the server is used in the case of a.js(10KB) and ringing headers (1KB).

Strong cache

Expires

This is an HTTP 1.0 field that represents the cache expiration time, which is an absolute time (current time + cache time). In the response header, the browser compares the current time with its value before requesting the resource and does not need to request it again if it has not expired.

A new cache. HTML

<! DOCTYPE html> <html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <link rel="icon" href="data:; base64,=">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>cache</title>
  <script src="cache.js"></script>
</head>
<body>
  <h1>cache</h1>
</body>
</html>
Copy the code

A new cache. Js

let http = require('http'),
fs = require('fs'),
path = require('path'),
url = require("url")
http.createServer((req,res)=>{
  letpathname = __dirname + url.parse(req.url).pathname; // Get the file pathletStatusCode = 200 // response header statusCodeletExtname = path.extName (pathname) // Obtain the file name extensionlet headType = 'text/html'// Content typeif( extname){
    switch(extname){
      case '.html':
       headType = 'text/html'
      break;
      case '.js':
        headType = 'text/javascript'
      break;
    }
  }
  fs.readFile(pathname, function (err, data) {
    res.writeHead(statusCode, {
      'Content-Type': headType,
      'Expires':new Date(date.now () + 10000).toutcString () // Set file expiration time to 10 seconds}); res.end(data); }); }).listen(3000) console.log("Server running at http://127.0.0.1:3000/");
Copy the code

Start the

node cache.js
Copy the code

Open a browser to http://127.0.0.1:3000/cache.html to check the network

  1. First access to all network request resources
  2. Reload from memory within 10sfrom memory cache)
  3. 10 seconds to close TAB, reopen the requested cache.html, load from disk (from disk cache)
  4. 10 seconds later, the cache is invalid. Repeat step 1

Disadvantages:

  1. ExpiresExpiration control is unstable. Because if we change the computer’s local time, the browser will determine that the cache is invalid.

Cache-control

This is an HTTP1.1 field, which is a relative time ‘cache-control ‘:’max-age=20’ meaning 20 seconds to use the cached resource without requesting the server

Fs. readFile(pathname,function (err, data) {
    res.writeHead(statusCode, {
      'Content-Type': headType,
      'Cache-Control':'max-age=20'
    });
Copy the code

Cache-control has many attributes in addition to max-age relative expiration time

1. No-store: no content is cached 2. No-cache: cache, but before using the cache, the browser will ask the server to determine whether the cache is up to date. 3. Both the public client and proxy server (CDN) can be cached. 4

See cache-Control for more attributes

If you have a few questions here, why setting Expires or cache-Control to cache.html doesn’t work in Chrome. Cache-control: max-age=0 indicates that the browser does not use the Cache.

Chrome does something quite different: ‘cache-control’ is always set to ‘max-age=0 ‘, no matter if you press enter, f5 or ctrl+f5. Except if you start Chrome and enter the url and press enter.

pragma

Pragma is a legacy field from prior HTTP /1.1 and is defined only as backward compatibility with HTTP. No discussion here. Those who are interested can click to learn about Pragma

The node hot update

Here if you think every time you modifycache.jsAll files need to be re-executednode run cache.jsHere we can configure node hot update

npm init
npm i -D nodemon
Copy the code

NPM I -d stands for NPM install –save-dev

Modify the package. The json

"scripts": {
    "dev": "nodemon ./bin/www"
  },
Copy the code

We only need to run NPM run dev once

Comparison cache (negotiated cache)

The strong cache above still has a big flaw. When the set time expires, we have to ask the server for resources again, regardless of whether the file contents have changed. This is where the negotiation cache comes in.

Last-Modified

The response value returned by the server to the client regarding the most recent modification of the requested resource (GMT standard format)

If-Modified-Since

Request value sent by the client to the server for the last modification of the resource returned

The client saves the value and names it if-Modified-since. On a second request, the client sends an if-modified-since request to the server. The server compares the if-modified-since of the request header with the last-modified time of the server requested resource.

  1. If the resource has been modified: return the response resourcea.js(10kb)+ response headers(1kb), status code:200 OK
  2. If not modified: only the response header is returned(1kb), status code:304 Not Modified
// omit other codelet stat = fs.statSync(pathname);
  fs.readFile(pathname, function(err, data) {// Check whether the file modification time of the request header is equal to the file modification time of the serverif(req.headers['if-modified-since'] === stat.mtime.toutCString ()) {// mtime is the timestamp of the file content change statusCode = 304; } res.writeHead(statusCode, {'Content-Type': headType,
      'Last-Modified':stat.mtime.toUTCString()
    });
    res.end(data);    
  });
Copy the code


  1. last-modifiedIf the resource is modified multiple times within 1s, the value is in secondslast-modifiedNo change, the client will still use the cache.
  2. If the resource requested on the server (a.js) has been Modified, but the actual contents of the file have not changed at all. The last-modified time does not match, so it will be returned to the browser (example: the server dynamically generates the file).

To solve the problem, use the new fields ETag and if-none-match

ETag

Response value, a unique value calculated by the server to the client based on the contents of the file (GMT standard format)

If-Not-Match

Request value, sent by the client to the server to return the last resource unique value

The request process is the same as last-Modified

The above last_modified consists of mtime, whereas ETag consists of last_modified and content_length

Fs. readFile(pathname,function (err, data) {
    let Etag = `${data.length.toString(16)}${stat.mtime.toString(16)}`
    if((req.headers['if-modified-since'] === stat.mtime.toUTCString()) || (req.headers['if-none-match'] === Etag)) {
      statusCode = 304;
    }
    res.writeHead(statusCode, {
      'Content-Type': headType,
      Etag
    });
    res.end(data);    
  });
Copy the code

Cache priority

When multiple caches exist at the same time, which one does the browser use? So you have a priority relationship here

  • If strong cache and negotiated cache exist at the same time, the cache is forced if the strong cache is still in effect. Otherwise, negotiated cache is used. (Strong cache priority > Contrast cache priority)
  • Strong cacheexpiresandcache-controlWhen they coexist,cache-controloverwriteexpires (cache-controlPriority >expiresPriority.)
  • Compared to the cacheEtagandLast-ModifiedWhen they coexist,EtagoverwriteLast-ModifiedEffect. (ETagPriority >Last-Modified) priority.

Best practices

This is just to give you a better overview of HTTP caching, but how can we use caching to achieve a better user experience in the real world? Webpack everybody is believed to have no stranger, if the actual configuration experience students must remember our exports in the configuration file output or packaging picture filename tend to add hash | | chunkhash | | contenthash these fields

module.exports = {
     output:{
        path:path.resolve(__dirname,'.. /dist'),
        filename:'js/[name].[contenthash:8].js',
        chunkFilename:'js/[name].[chunkhash:8].js'
    },
    loader:{
        rules:[
             {
                test:/\.(jep? g|png|gif)$/, use:{ loader:'url-loader',
                  options:{
                    limit:10240,
                    fallback:{
                      loader:'file-loader',
                      options:{
                        name:'img/[name].[hash:8].[ext]'}}}}}]}}Copy the code

The resulting file name is usually as follows

Finally, the impact of user behavior on the browser cache is included

Develop reading

Interview picks for HTTP caching