二十四.浏览器的协商缓存与服务器的自启动

  • 概述
    协商缓存:
        1. 客户端向服务端发送一个请求,请求相应的资源
        2. 服务端向客户端发送一个响应,在响应头中携带两个关于缓存的信息,分别是 当前文件的唯一标识(eTag)和 当前文件的最后一次修改时间(last-modified)
        3. 客户端收到了响应文件和关于文件的缓存信息,并把缓存信息保存在客户端,但是更换了名称,把eTag更名为if-none-match,把last-modified更名为if-modified-since。
        4. 客户端第二次请求服务端,请求相应的资源,会在请求头上携带两个字段,就是之前已经请求过的文件的缓存信息 if-none-match和if-modified-since
        5. 服务端接收到了客户端的if-none-match和if-modified-since,然后会重新获取被请求文件的eTag和last-modified,然后开始比较,如果两个都比较成功,则读取缓存,否则返回新的响应
        6.如果走缓存,则服务端的响应状态码是304,并且不需要设置任何的响应内容
        7.如果走缓存,则客户端接收到的状态码是304,并直接去读取缓存
        8.如果不走缓存,则响应状态码是200,并且响应最新的数据,还要携带最新的eTag和last-modified
    
  • web页面如下
    <!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>
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    </head>
    
    <body>
        <h1>协商缓存</h1>
        <ul>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
        </ul>
    </body>
    </html>
    
  • 协商缓存与服务器的自启动
    const express = require("express");
    const {
        exec
    } = require("child_process")
    const path = require("path");
    const etag = require("etag");
    const {
        promisify
    } = require("util");
    const fs = require("fs");
    const {
        resolve6
    } = require("dns");
    const app = express();
    app.get("/", async (req, res) => {
        // sendFile已经把协商缓存设置好了
        /* const filePath = path.resolve(__dirname, "./index.html");
        res.sendFile(filePath) */
        //在接收请求的时候,先获取请求头携带的if-none-match 和 if-modified-since
        const ifNoneMatch = req.headers["if-none-match"];
        const ifModifiedSince = req.headers["if-modified-since"];
        console.log(ifNoneMatch, ifModifiedSince);
    
        const filePath = path.resolve(__dirname, "./index.html");
        const rs = fs.createReadStream(filePath);
    
        //fs有一个stat方法 可以得到文件的详细信息
        //使用promisify方法把stat方法包装成promise对象
        const stat = promisify(fs.stat);
    
        //得到文件详细的信息
        const fileDetail = await stat(filePath);
        // console.log(fileDetail);
    
        //得到文件的最后修改时间
        const fileTime = fileDetail.mtime.toGMTString();
        //得到文件的唯一标识
        const fileEtag = etag(fileDetail);
        // console.log(fileTime.toString(), fileEtag);
    
        //协商缓存判断
        if (ifNoneMatch === fileEtag && ifModifiedSince === fileTime) {
            return res.status(304).end()
        }
        //把文件的唯一标识和最后修改时间设置在响应头中
        res.set("ETag", fileEtag);
        res.set("Last-Modified", fileTime);
        rs.pipe(res);
    })
    app.listen("3000", (err) => {
        if (err) {
            console.log(err);
            return;
        }
        console.log("服务已经启动  http://127.0.0.1:3000");
        // exec("start http://127.0.0.1:3000")
    })
    
上一篇:前端面试百分之九十九过的技巧(二)


下一篇:浏览器缓存策略