1. 程式人生 > 其它 >二十四.瀏覽器的協商快取與伺服器的自啟動

二十四.瀏覽器的協商快取與伺服器的自啟動

  • 概述
    協商快取:
        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")
    })