1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        前端需要知道的緩存知識(shí)總結(jié)

        共 8830字,需瀏覽 18分鐘

         ·

        2024-05-22 23:15

           

        大廠技術(shù)  高級(jí)前端  Node進(jìn)階

        點(diǎn)擊上方 程序員成長(zhǎng)指北,關(guān)注公眾號(hào)

        回復(fù)1,加入高級(jí)Node交流群

        引言??

        HTTP緩存是一種用于提高網(wǎng)站性能和減少帶寬使用的技術(shù)。當(dāng)用戶訪問(wèn)一個(gè)網(wǎng)頁(yè)時(shí),瀏覽器會(huì)下載頁(yè)面上的所有資源(如HTML、CSS、JavaScript等),這些資源會(huì)占用大量的帶寬和時(shí)間。為了減少這些資源的加載時(shí)間,HTTP緩存機(jī)制被引入。???

        緩存分為強(qiáng)緩存協(xié)商緩存兩種,強(qiáng)緩存不能緩存地址欄訪問(wèn)的文件,協(xié)商緩存可以緩存地址欄訪問(wèn)的文件。

        1、強(qiáng)緩存??

        由服務(wù)器設(shè)置過(guò)期時(shí)間,在該時(shí)間到期之前,瀏覽器會(huì)直接從本地緩存中獲取資源。

        強(qiáng)緩存的實(shí)現(xiàn)方式有兩種:ExpiresCache-Control。

        1.1、Expires??????????

        Expires 是 HTTP 緩存機(jī)制中實(shí)現(xiàn)強(qiáng)緩存的一種方式,它通過(guò)在響應(yīng)頭部中加入一個(gè)過(guò)期時(shí)間來(lái)控制緩存。Expires 的值是一個(gè)日期,格式為:Wed, 21 Oct 2015 07:28:00 GMT。它表示該資源的過(guò)期時(shí)間。當(dāng)瀏覽器再次請(qǐng)求該資源時(shí),會(huì)判斷是否在該過(guò)期時(shí)間內(nèi),如果是則直接從緩存中獲取資源,否則重新向服務(wù)器請(qǐng)求。

        要設(shè)置 Expires 頭部,需要在服務(wù)器端進(jìn)行配置。例如,在 Nginx 中可以使用expires指令來(lái)設(shè)置過(guò)期時(shí)間:

        location / {
        expires 1h;
        }

        注意??:由于Expires是基于客戶端時(shí)間計(jì)算的,如果客戶端的時(shí)間與服務(wù)器的時(shí)間不一致,則可能會(huì)影響緩存效果。

        1.2、Cache-Control??????????

        Cache-Control 是通過(guò)在響應(yīng)頭部中加入 Cache-Control 字段,并設(shè)置max-age值來(lái)表示該資源在多少秒內(nèi)有效(即緩存的最大時(shí)長(zhǎng))。

        Cache-Control響應(yīng)頭的最常用格式為:

        Cache-Control: max-age=<seconds> // seconds 是緩存的時(shí)間,單位是秒

        當(dāng)瀏覽器請(qǐng)求資源得到的響應(yīng)頭中帶有 Cache-Control 響應(yīng)頭時(shí),瀏覽器會(huì)將該資源緩存到本地。在下一次訪問(wèn)該資源時(shí),同時(shí)滿足下述條件,瀏覽器就會(huì)使用本地資源(即緩存),而不重新去服務(wù)器請(qǐng)求該資源:

        1. 緩存時(shí)間未過(guò)期
        2. URL未發(fā)生變化
        3. 請(qǐng)求頭中沒(méi)有 Cache-Control: no-cachePragma: no-cache 這兩個(gè)信息(強(qiáng)制刷新會(huì)在請(qǐng)求頭中添加 Cache-Control: no-cache

        注意??:直接通過(guò)瀏覽器的地址欄訪問(wèn)的資源緩存會(huì)失效(跟強(qiáng)制刷新一樣會(huì)在請(qǐng)求頭中添加 Cache-Control: no-cache

        接下來(lái)我們通過(guò)一個(gè)簡(jiǎn)單的頁(yè)面來(lái)實(shí)踐一下:

        目錄結(jié)構(gòu),我們準(zhǔn)備兩個(gè)文件 index.jsindex.html ,再準(zhǔn)備兩張圖片:

        http
        |--- index.js
        |--- index.html
        |--- 1.jpg
        |___ 2.jpg

        index.js

        提供一個(gè) node 服務(wù),用于返回瀏覽器請(qǐng)求的資源(index.html 和圖片)

        // index.js
        const http = require('http')
        const fs = require('fs')
        const path = require('path')

        const server = http.createServer((req, res) => {

          let filePath = path.resolve(__dirname, req.url === '/' ? `index.html` : '1.jpg')

          res.writeHead(200, {
            'Content-Type': req.url === '/' ? 'text/html; charset=utf-8' : 'image/png',
            'Cache-Control''max-age=86400'// 緩存一天
          })
          const fileStream = fs.createReadStream(filePath)
          return fileStream.pipe(res)
        })

        server.on('clientError', (err, socket) => {
          socket.end('HTTP/1.1 400 Bad Request\r\n\r\n')
        })

        server.listen(8080, () => {
          console.log(`opened server on http://localhost:${server.address().port}`)
        })

        index.html

        一個(gè)簡(jiǎn)單的頁(yè)面,包含一張圖片,因?yàn)槲覀儠?huì)直接通過(guò)瀏覽器的地址欄訪問(wèn) html,所以 html 的緩存策略會(huì)失效。這里我們判斷緩存是否生效是通過(guò)頁(yè)面中的圖片去判斷的。

        <!-- 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>Hello World</title>
        </head>
        <body>
          <h1>Hello World!</h1>
          <!-- 別忘記替換成你的圖片名稱 -->
          <img src="./1.jpg" title="123">
        </body>
        </html>

        然后隨便準(zhǔn)備兩張圖片就可以了,我們?cè)陧?xiàng)目的跟目錄使用 node index.js 來(lái)啟動(dòng)項(xiàng)目。如下圖提示,就表示啟動(dòng)成功,然后我們通過(guò)瀏覽器訪問(wèn) http://localhost:8080/ 就能看到我們的頁(yè)面了。

        image.png

        首次請(qǐng)求 我們主要看圖片的請(qǐng)求頭跟響應(yīng)頭就行(因?yàn)閔tml的緩存會(huì)失效)。

        image.png
        image.png

        刷新頁(yè)面(非強(qiáng)制刷新)

        第二次的請(qǐng)求可以看到請(qǐng)求的 Size 變成了 memory cache,并且 Time 也變?yōu)榱?0。再進(jìn)一步看請(qǐng)求頭和響應(yīng)頭,請(qǐng)求頭中的 Cache-Control: no-cache 屬性沒(méi)有了,并且瀏覽器會(huì)給出一個(gè)警告:Provisional headers are shown. Disable cache to see full headers.。大致意思就是當(dāng)前使用的是緩存的臨時(shí)文件,禁用緩存后才可以查看完整的請(qǐng)求頭。

        image.png
        image.png

        驗(yàn)證緩存

        上述的方法可能并不一定讓你相信我們使用的是緩存文件,而不是重新請(qǐng)求的資源文件。

        一開始我們準(zhǔn)備了兩張圖片,現(xiàn)在使用的是 1.jpg,還有一個(gè) 2.jpg,我們把 1.jpg 刪除了,然后把2.jpg 改名成 1.jpg,然后刷新頁(yè)面(非強(qiáng)制刷新),就會(huì)發(fā)現(xiàn)雖然我們圖片更改了,但是圖片并不是我們后面改名的那個(gè)圖片,還是之前的圖片。

        image.png

        強(qiáng)制刷新后就能看到,我們替換的圖片生效了,請(qǐng)求頭中也帶上了 Cache-Control: no-cache 屬性。

        image.png

        2、協(xié)商緩存

        利用瀏覽器和服務(wù)器之間的通信來(lái)確定是否需要重新獲取資源。

        協(xié)商緩存有兩種實(shí)現(xiàn)方式:If-Modified-SinceETag

        當(dāng)瀏覽器第一次請(qǐng)求資源時(shí),服務(wù)器會(huì)返回該資源的 ETag 值和 Last-Modified 時(shí)間。當(dāng)瀏覽器再次請(qǐng)求該資源時(shí),它會(huì)將這些值作為請(qǐng)求頭部的 If-Modified-SinceIf-None-Match 字段發(fā)送給服務(wù)器。服務(wù)器會(huì)比較這些值與資源的當(dāng)前狀態(tài),如果資源沒(méi)有發(fā)生變化,服務(wù)器返回 304 Not Modified 響應(yīng),告訴瀏覽器可以使用緩存的資源。

        如果資源已經(jīng)發(fā)生了變化,服務(wù)器會(huì)返回新的資源,并更新 ETagLast-Modified 。

        2.1、If-Modified-Since ??????????

        利用響應(yīng)頭的 Last-Modified 來(lái)設(shè)置緩存,并在下次請(qǐng)求的請(qǐng)求頭中攜帶 If-Modified-Since 來(lái)判斷該資源是否發(fā)生變化,如果發(fā)生變化則返回新的資源,并更新 Last-Modified 屬性,如果沒(méi)有發(fā)生變化,則返回 304 跟空的 body

        對(duì)強(qiáng)緩存的例子稍微修改一下

        // index.js
        const http = require('http')
        const fs = require('fs')
        const path = require('path')

        const server = http.createServer((req, res) => {
          let filePath = path.resolve(__dirname, req.url === '/' ? `index.html` : '1.jpg')
          const stat = fs.statSync(filePath)
          const lastModified = stat.mtime.toUTCString()
          const header = {
            'Content-Type': req.url === '/' ? 'text/html; charset=utf-8' : 'image/png',
            'Last-Modified': lastModified
          }
          // 判斷資源是否發(fā)生變化
          if (req.headers['if-modified-since'] === lastModified) {
            res.writeHead(304, header)
            res.end()
          } else {
            res.writeHead(200, header)
            const fileStream = fs.createReadStream(filePath)
            return fileStream.pipe(res)
          }
        })

        server.on('clientError', (err, socket) => {
          socket.end('HTTP/1.1 400 Bad Request\r\n\r\n')
        })

        server.listen(8080, () => {
          console.log(`opened server on http://localhost:${server.address().port}`)
        })

        首次請(qǐng)求

        響應(yīng)頭攜帶 Last-Modified: Mon, 05 Jun 2023 08:57:17 GMT 屬性,告訴瀏覽器這個(gè)文件需要緩存。

        image.png

        刷新頁(yè)面(非強(qiáng)制刷新)

        第二次請(qǐng)求,響應(yīng)狀態(tài)碼變?yōu)?304,并在請(qǐng)求頭中攜帶 If-Modified-Since: Mon, 05 Jun 2023 08:57:17 GMT 屬性,表示瀏覽器使用緩存文件。

        image.png

        改變html文件

        把 html 中 的 Hello World! 改為 Web Html,并刷新頁(yè)面(非強(qiáng)制刷新),發(fā)現(xiàn)響應(yīng)狀態(tài)碼變?yōu)?200 ,并且更新了頁(yè)面和響應(yīng)頭的 Last-Modified 屬性。

        image.png

        注意??:如果資源的修改時(shí)間只精確到秒,而不是毫秒,可能會(huì)導(dǎo)致緩存失效。此外,如果服務(wù)器上的資源被修改了,但修改時(shí)間沒(méi)有更新,也會(huì)導(dǎo)致緩存失效

        2、ETag ??????????

        ETag 基本上與 If-Modified-Since 一致, 利用響應(yīng)頭的 Etag 來(lái)設(shè)置緩存,并在下次請(qǐng)求的請(qǐng)求頭中攜帶 if-none-match 來(lái)判斷該資源是否發(fā)生變化,如果發(fā)生變化則返回新的資源,并更新 Etag 屬性,如果沒(méi)有發(fā)生變化,則返回 304 跟空的 body。

        const http = require('http')
        const fs = require('fs')
        const path = require('path')
        const crypto = require('crypto')

        const server = http.createServer((req, res) => {
          let filePath = path.resolve(__dirname, req.url === '/' ? `index.html` : '1.jpg')
          const fileContent = fs.readFileSync(filePath)
          const hash = crypto.createHash('md5').update(fileContent).digest('hex')
          const etag = `"${hash}"` // etag需要加雙引號(hào)
          const header = {
            'Content-Type': req.url === '/' ? 'text/html; charset=utf-8' : 'image/png',
            'Etag': etag
          }
          if (req.headers['if-none-match'] === etag) {
            res.writeHead(304, header)
            res.end()
          } else {
            res.writeHead(200, header)
            const fileStream = fs.createReadStream(filePath)
            return fileStream.pipe(res)
          }
        })

        server.on('clientError', (err, socket) => {
          socket.end('HTTP/1.1 400 Bad Request\r\n\r\n')
        })

        server.listen(8080, () => {
          console.log(`opened server on http://localhost:${server.address().port}`)
        })

        這里的測(cè)試證明就不寫,不然這文章的字?jǐn)?shù)就太水了,如果你們有興趣可以自己嘗試一下

        原文:https://juejin.cn/post/7241095368179957820

        作者:——樹深遇鹿

        Node 社群

            


        我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。

           “分享、點(diǎn)贊、在看” 支持一下

        瀏覽 196
        2點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        2點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            操逼视频软件 | ass日本少妇pics | 美女艹逼视频网站 | 逼免费看| 欧美成人考逼视频 | 色噜噜在线视频 | 看黄色一级 | 日日日日日夜夜夜夜夜 | 亚洲天堂人妻 | 一边洗澡一边摸一边做视频 |