当前位置:网站首页>No nonsense, code practice will help you master strong caching and negotiation caching!

No nonsense, code practice will help you master strong caching and negotiation caching!

2022-06-25 21:49:00 Sunshine_ Lin

Preface

Hello everyone , I'm Lin Sanxin , Speak the most difficult knowledge points in the most easy to understand words It's my motto , Foundation is the premise of advanced It's my first heart

background

Whether in development or interview ,HTTP cache It's all very important , This is reflected in two aspects :

  • In development : Reasonable use HTTP cache It can improve the performance of front-end pages
  • During the interview HTTP cache It's a high-frequency question in the interview

So this article , I don't talk nonsense , I'll go through Nodejs The simple practice of , The most easy to understand HTTP cache , Through this article, you will be able to understand and master it !!!

Lead to

Get ready

  • Create folder cache-study , And prepare the environment

    npm init
  • install Koa、nodemon

    npm i koa -D
    npm i nodemon -g
  • establish index.js、index.html、static Folder
  • index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./static/css/index.css">
    </head>
    <body>
    <div class="box">
    
    </div>
    </body>
    </html>
  • static/css/index.css

    .box {
    width: 500px;
    height: 300px;
    background-image: url('../image/guang.jpg');
    background-size: 100% 100%;
    color: #000;
    
    }
  • static/image/guang.jpg

  • index.js

    const Koa = require('koa')
    const fs = require('fs')
    const path = require('path')
    const mimes = {
    css: 'text/css',
    less: 'text/css',
    gif: 'image/gif',
    html: 'text/html',
    ico: 'image/x-icon',
    jpeg: 'image/jpeg',
    jpg: 'image/jpeg',
    js: 'text/javascript',
    json: 'application/json',
    pdf: 'application/pdf',
    png: 'image/png',
    svg: 'image/svg+xml',
    swf: 'application/x-shockwave-flash',
    tiff: 'image/tiff',
    txt: 'text/plain',
    wav: 'audio/x-wav',
    wma: 'audio/x-ms-wma',
    wmv: 'video/x-ms-wmv',
    xml: 'text/xml',
    }
    
    //  Get the type of file 
    function parseMime(url) {
    // path.extname Get the suffix of the file in the path 
    let extName = path.extname(url)
    extName = extName ? extName.slice(1) : 'unknown'
    return mimes[extName]
    }
    
    //  Convert the file to the format required for transmission 
    const parseStatic = (dir) => {
    return new Promise((resolve) => {
      resolve(fs.readFileSync(dir), 'binary')
    })
    }
    
    const app = new Koa()
    
    app.use(async (ctx) => {
    const url = ctx.request.url
    if (url === '/') {
      //  Access the root path and return index.html
      ctx.set('Content-Type', 'text/html')
      ctx.body = await parseStatic('./index.html')
    } else {
      const filePath = path.resolve(__dirname, `.${url}`)
      //  Set type 
      ctx.set('Content-Type', parseMime(url))
      //  Set transmission 
      ctx.body = await parseStatic(filePath)
    }
    })
    
    app.listen(9898, () => {
    console.log('start at port 9898')
    })

    Launch page

    Now you can enter... In the terminal nodemon index , See the display below , It means that the service has been started successfully

At this point, you can enter... In the browser link http://localhost:9898/ , Open and see the following page , It means that the page is accessed successfully !!!

HTTP Cache type

HTTP cache There are two common types of :

  • Strong cache : It can be determined by one of these two fields

    • expires
    • cache-control( Higher priority )
  • Negotiate the cache : It can be determined by one of these two pairs of fields

    • Last-Modified,If-Modified-Since
    • Etag,If-None-Match( Higher priority )

Strong cache

Let's start with Strong cache

expires

We just need to set the response header expires At current time + 30s That's it

app.use(async (ctx) => {
  const url = ctx.request.url
  if (url === '/') {
    //  Access the root path and return index.html
    ctx.set('Content-Type', 'text/html')
    ctx.body = await parseStatic('./index.html')
  } else {
    const filePath = path.resolve(__dirname, `.${url}`)
    //  Set type 
    ctx.set('Content-Type', parseMime(url))
    //  Set up  Expires  Response head 
    const time = new Date(Date.now() + 30000).toUTCString()
    ctx.set('Expires', time)
    //  Set transmission 
    ctx.body = await parseStatic(filePath)
  }
})

Then we refresh the front page , We can see that there is one more in the response header of the requested resource expires Field of

also , stay 30s Inside , After we refresh , See the request is to go memory , It means , adopt expires The time effect of setting strong cache is 30s, this 30s within , Resources will go to the local cache , Instead of re requesting

Be careful : Sometimes you Nodejs Code update aging time , However, it is found that the front-end page is still on the time limit of the code , This is the time , You can put this Disabled cache Hook , Then refresh , Cancel... Tick again

cache-control

Actually cache-control Follow expires The effect is almost the same , It's just that the values of these two fields are different , The former is set to Number of seconds , The latter is set to Number of milliseconds

app.use(async (ctx) => {
  const url = ctx.request.url
  if (url === '/') {
    //  Access the root path and return index.html
    ctx.set('Content-Type', 'text/html')
    ctx.body = await parseStatic('./index.html')
  } else {
    const filePath = path.resolve(__dirname, `.${url}`)
    //  Set type 
    ctx.set('Content-Type', parseMime(url))
    //  Set up  Cache-Control  Response head 
    ctx.set('Cache-Control', 'max-age=30')
    //  Set transmission 
    ctx.body = await parseStatic(filePath)
  }
})

There are too many response headers on the front-end page cache-control This field , And 30s Go to local cache in the , I won't ask the server

Negotiate the cache

And Strong cache The difference is , Strong cache Is within the time limit , Don't go to the server , Only local cache ; and Negotiate the cache It's the server side , If you request a resource , When you go to the server , Find out Hit cache Then return to 304 , Otherwise, the requested resource is returned , What's that Hit cache Well ? Let's talk about that

Last-Modified,If-Modified-Since

In a nutshell :

  • The first time a resource is requested , The server will send the requested resources to Last modification time As in the response header Last-Modified Send the value to the browser and save it in the browser
  • The second time a resource is requested , The browser will treat the time just stored as the request header If-Modified-Since Value , To the server , The server obtains this time and compares it with the last modification time of the requested resource
  • If the two times are the same , It means that this resource has not been modified , That's it Hit cache , Then return 304 , If it's not the same , It indicates that this resource has been modified , be Miss cache , The modified new resource is returned
//  Get file information 
const getFileStat = (path) => {
  return new Promise((resolve) => {
    fs.stat(path, (_, stat) => {
      resolve(stat)
    })
  })
}

app.use(async (ctx) => {
  const url = ctx.request.url
  if (url === '/') {
    //  Access the root path and return index.html
    ctx.set('Content-Type', 'text/html')
    ctx.body = await parseStatic('./index.html')
  } else {
    const filePath = path.resolve(__dirname, `.${url}`)
    const ifModifiedSince = ctx.request.header['if-modified-since']
    const fileStat = await getFileStat(filePath)
    console.log(new Date(fileStat.mtime).getTime())
    ctx.set('Cache-Control', 'no-cache')
    ctx.set('Content-Type', parseMime(url))
    //  Compare time ,mtime Is the last modification time of the file 
    if (ifModifiedSince === fileStat.mtime.toGMTString()) {
      ctx.status = 304
    } else {
      ctx.set('Last-Modified', fileStat.mtime.toGMTString())
      ctx.body = await parseStatic(filePath)
    }
  }
})

On the first request , In the response header :

On second request , Request header :

Because the resource has not been modified , Then hit cache , return 304:

At this point, let's modify index.css

.box {
  width: 500px;
  height: 300px;
  background-image: url('../image/guang.jpg');
  background-size: 100% 100%;
  /*  Modify here  */
  color: #333;
}

Then let's refresh the page , index.css Changed , So will Miss cache , return 200 And new resources , and guang.jpg No modification , be Hit cache return 304:

Etag,If-None-Match

Actually Etag,If-None-Match Follow Last-Modified,If-Modified-Since Roughly the same , The difference lies in :

  • The latter is the last modification time of the comparison resource , To determine whether the resource has been modified
  • The former is to compare the content of resources , To determine whether the resource is modified

How do we compare the content of resources ? We just need to read the content of the resource , Turn into hash value , Just compare it before and after !!

const crypto = require('crypto')

app.use(async (ctx) => {
  const url = ctx.request.url
  if (url === '/') {
    //  Access the root path and return index.html
    ctx.set('Content-Type', 'text/html')
    ctx.body = await parseStatic('./index.html')
  } else {
    const filePath = path.resolve(__dirname, `.${url}`)
    const fileBuffer = await parseStatic(filePath)
    const ifNoneMatch = ctx.request.header['if-none-match']
    //  Production content hash value 
    const hash = crypto.createHash('md5')
    hash.update(fileBuffer)
    const etag = `"${hash.digest('hex')}"`
    ctx.set('Cache-Control', 'no-cache')
    ctx.set('Content-Type', parseMime(url))
    //  contrast hash value 
    if (ifNoneMatch === etag) {
      ctx.status = 304
    } else {
      ctx.set('etag', etag)
      ctx.body = fileBuffer
    }
  }
})

The verification method is the same as just Last-Modified,If-Modified-Since The same as , I won't repeat it here ...

summary

Reference material

Conclusion

I'm Lin Sanxin , An enthusiastic front-end rookie programmer . If you make progress , Like the front , Want to learn the front end , Then we can make friends , Fish together, ha ha , Fish schools , Add me, please note 【 Think no 】

image.png

原网站

版权声明
本文为[Sunshine_ Lin]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202181224221282.html