当前位置:网站首页>Practical examples of node strong cache and negotiation cache

Practical examples of node strong cache and negotiation cache

2022-07-04 20:29:00 1024 questions

Catalog

Preface

What is browser caching

advantage

Strong cache

Expires

Cache-Control

Negotiate the cache

Last-Modified、If-Modified-Since

ETag、If-None-Match

node practice

koa Start the service

Create project

koa Code

Start the service

Native koa Realize simple static resource service

Define resource type list

Resolve the requested resource type

fs Read the file

koa Handle

Strong cache validation

Set up Expire

Cache-Control

Negotiate cache validation

Last-Modified,If-Modified-Since

etag、If-None-Match

Summary

summary

Preface

Browser caching is a very important solution for performance optimization , Using cache reasonably can improve the user experience , It can also save the cost of the server . Mastering the principle and reasonable use of cache is very important for both front-end and operation and maintenance .

What is browser caching

Browser cache (http cache ) It refers to that the browser stores the documents recently requested by the user on the local disk , When visitors visit the same page again , The browser can load the document directly from the local disk .

advantage

Reduced redundant data transfer , Save bandwidth , Reduce server pressure

Speed up client loading , Enhance user experience .

Strong cache

Strong caching does not send requests to the server , Instead, read resources directly from the cache , Strong caching can be set in two ways HTTP Header Realization :Expires and Cache-Control, These two heads are HTTP1.0 and HTTP1.1 The implementation of the .

Expires

Expires yes HTTP1.0 A method is proposed to represent the resource expiration time header, It describes an absolute time , Returned by server .

Expires Limited by local time , If the local time is changed , Will cause cache invalidation .

Cache-Control

Cache-Control Appear in HTTP/1.1, Common fields are max-age, The unit is seconds , quite a lot web Servers have default configurations , Priority over Expires, It means relative time .

for example Cache-Control:max-age=3600 The validity period of the representative resource is 3600 second . Take the... In the response header Date, Time the request was sent , Indicates that the current resource is in Date ~ Date +3600s It's effective all this time .Cache-Control It also has multiple values :

no-cache Don't use cache directly , That is, skip strong cache .

no-store Disable browsers from caching data , Each request for resources will ask the server for complete resources .

public It can be cached by all users , Including end users and CDN Such as middleware proxy server .

private Only end users' browsers are allowed to cache , Other intermediate proxy servers are not allowed to cache .

It's important to note that no-cache and no-store The difference between ,no-cache Skip strong cache , I will still go through the steps of negotiating caching , and no-store It's really not going to cache at all , All resources will not be cached locally

Negotiate the cache

When a browser's request for a resource fails to hit the strong cache , A request will be sent to the server , Verify that the negotiation cache hits , If the negotiation cache hits , Response to the request http Status as 304 And it will show a Not Modified String .

The negotiation cache uses 【Last-Modified,If-Modified-Since】 and 【ETag、If-None-Match】 These two pairs Header To manage .

Be careful !! Negotiation cache needs to be used with strong cache , To use negotiation cache, you need to set Cache-Control:no-cache perhaps pragma:no-cache To tell the browser not to strengthen the cache

Last-Modified、If-Modified-Since

these two items. Header yes HTTP1.0 Version of , The two fields are used together .

Last-Modified Indicates the last modification date of the local file , The browser will be on the request header If-Modified-Since( Last time back Last-Modified Value ), The server will match this value with the time of resource modification , If the time is inconsistent , The server will return a new resource , And will Last-Modified Value update , Return to the browser as a response header . If the time is the same , Indicates that the resource is not updated , Server return 304 Status code , After getting the response status code, the browser reads the resource from the local cache .

but Last-Modified There are several problems .

Although the file has been modified , But the final content has not changed , In this way, the modification time of the file will still be updated

Some files are modified within seconds , At this time, it is not enough to record in seconds

Some servers cannot accurately obtain the last modification time of the file .

So it's here ETAG.

ETag、If-None-Match

stay HTTP1.1 In the version , Server pass Etag To set the response header cache id .Etag The value of is generated by the server . On the first request , The server will transfer resources and Etag Return to browser , The browser caches both to the local cache database . On the second request , The browser will Etag Put information in If-None-Match The request header accesses the server , After the server receives the request , It will compare the file ID in the server with the ID sent by the browser , If it's not the same , The server returns the updated resources and the new Etag , If the same , Server return 304 Status code , The browser reads the cache .

Process summary

Summarize these fields :

Cache-Control —— Before requesting the server

Expires —— Before requesting the server

If-None-Match (Etag) —— Request server

If-Modified-Since (Last-Modified) —— Request server

node practice

This article uses koa For example , because koa It's more lightweight 、 More pure , There is no middleware bundled with it , comparison express I brought a lot of router、static And other middleware functions ,koa It is more suitable for this article as an example .

koa Start the service

With the purpose of learning and being easier to understand , Don't use koa-static and koa-router middleware , use koa Simple implementation web Server to verify the previous conclusion .

Create project # Create and enter a directory and create index.js file mkdir koa-cachecd koa-cachetouch index.js# Initialize project git inityarn init# take koa Install as local dependency yarn add koakoa Code /*app.js*/const Koa = require('koa')const app = new Koa()app.use(async (ctx) => { ctx.body = 'hello koa'})app.listen(3000, () => { console.log('starting at port 3000')}) Start the service node index.js

Such a koa The service is up , visit localhost:3000 You can see hello koa.

For the convenience of debugging , Modify the code without restarting , Recommended nodemon perhaps pm2 Start the service .

Native koa Realize simple static resource service

The key point of implementing a static resource server is to judge the requested resource type according to the address requested by the front end , Set the returned Content-Type, Let the browser know the content type returned , The browser can decide in what form , What code to read the returned content .

Define resource type list 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',} Resolve the requested resource type 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]}fs Read the file const parseStatic = (dir) => { return new Promise((resolve) => { resolve(fs.readFileSync(dir), 'binary') })}koa Handle 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 { ctx.set('Content-Type', parseMime(url)) ctx.body = await parseStatic(path.relative('/', url)) }})

This basically completes a simple static resource server . Then create a new one in the root directory html Document and static Catalog , And in static Put down some files . At this time, the directory should be like this :

|-- koa-cache |-- index.html |-- index.js |-- static |-- css |-- color.css |-- ... |-- image |-- soldier.png |-- ... ... ...

It's time to go through localhost:3000/static Access the specific resource file .

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>test cache</title> <link rel="stylesheet" href="/static/css/index.css" rel="external nofollow" /> </head> <body> <div id="app"> test css file </div> <img src="/static/image/soldier.png" alt="" /> </body></html>

css/color.css

#app { color: blue;}

Open at this time localhost:3000, You can see the following effect :

The basic environment here will be set up . Next, enter the verification stage .

Strong cache validation

Before there is any configuration , May have a look network:

At this time, no matter for the first time or for several times , Will request resources from the server .

Be careful !!! Before starting the experiment network Panel Disable cache Check out , This option means to disable browser caching , The browser request will bring Cache-Control: no-cache and Pragma: no-cache Header information , At this time, all requests will not go to the cache

Set up Expire

modify index.js Medium app.use Code segment .

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}`) ctx.set('Content-Type', parseMime(url)) // Set the expiration time at 30000 millisecond , That is to say 30 Seconds later ctx.set('Expires', new Date(Date.now() + 30000)) ctx.body = await parseStatic(filePath) }})

use ctx.set(‘Expires’, new Date(Date.now() + 30000)), Set the expiration time to the current time 30000 millisecond , That is to say 30 Seconds later ( The following setting header information is modified here ).

Visit again localhost:3000, You can see more Expires This Header.

There is 30 You can see it in seconds network Of Size,css The file shows disk cache, and image Resources show from memory cache. At this time, the browser cache is read directly , No request server , You can try css Change the name or delete the image file to verify , Page display normal , Explain that the previous conclusion is correct .

Cache-Control

ctx.set(‘Cache-Control’, ‘max-age=300’) Set up 300 Seconds valid , The verification method is the same as above .

Negotiate cache validation Last-Modified,If-Modified-Since

HTTP1.0 The key point of negotiation cache is to bring according to the client request ifModifiedSince Field time and the corresponding modification time of the requested resource to determine whether the resource has been updated .

The first set Cache-Control: no-cache, So that the client does not strengthen the cache , Then judge whether the client request has a ifModifiedSince Field , Set without Last-Modified Field , And return the resource file . If you have it, use it fs.stat Read the modification time of the resource file , And make a comparison , If the time is the same , Then return the status code 304.

ctx.set('Cache-Control', 'no-cache') const ifModifiedSince = ctx.request.header['if-modified-since'] const fileStat = await getFileStat(filePath) if (ifModifiedSince === fileStat.mtime.toGMTString()) { ctx.status = 304 } else { ctx.set('Last-Modified', fileStat.mtime.toGMTString()) ctx.body = await parseStatic(filePath) }etag、If-None-Match

etag The key point of is to calculate the uniqueness of resource files , Use here nodejs Built in crypto Module to calculate the hash value , And expressed by hexadecimal string .cypto The usage of can see nodejs Its official website .

crpto Not only supports string encryption , It also supports incoming buffer encryption , As nodejs The built-in modules , The unique identification used to calculate the file here is very suitable .

ctx.set('Cache-Control', 'no-cache') const fileBuffer = await parseStatic(filePath) const ifNoneMatch = ctx.request.headers['if-none-match'] const hash = crypto.createHash('md5') hash.update(fileBuffer) const etag = `"${hash.digest('hex')}"` if (ifNoneMatch === etag) { ctx.status = 304 } else { ctx.set('etag', etag) ctx.body = fileBuffer }

The effect is as follows , The browser will bring the second request If-None-Match, The server calculates the of the file hash Values are compared again , Same returns 304, Different and then return to the new file . And if you modify the file , Of documents hash The value changes , At this time two hash Mismatch , The server returns the new file and brings the new file hash Value as etag.

Summary

Through the above code, the effect of each cache field is practiced , The code is only for demonstration , The production of static resource servers will be more complex , for example etag You won't get the file again every time to calculate the file hash value , It takes too much performance , Generally, there will be a response caching mechanism , For example, the demand for resources last-modified and etag Value to build index cache .

summary

Usually web Servers have default cache configurations , The specific implementation may also be different , image nginx、tomcat、express etc. web The server has the corresponding source code , Those who are interested can read and study .

Reasonable use of strong cache and negotiation cache depends on the use scenarios and requirements of the project . Like the current common single page application , Because packages are usually newly generated html And the corresponding static resource dependency , So you can be right html File configuration negotiation cache , And the dependencies generated by packaging , for example js、css These files can be strongly cached . Or use strong caching only for third-party libraries , Because third-party libraries usually have slow version updates , You can lock the version .

node Sample full code  https://github.com/chen-junyi/code/blob/main/node/cache/koa2.js

That's all node Details of practical examples of strong caching and negotiated caching , More about node For information about strong cache negotiation cache, please pay attention to other relevant articles on software development network !


原网站

版权声明
本文为[1024 questions]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/185/202207041835521759.html