<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          前端需要知道的緩存知識(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)求的資源文件。

          一開(kāi)始我們準(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è)試證明就不寫(xiě),不然這文章的字?jǐn)?shù)就太水了,如果你們有興趣可以自己嘗試一下

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

          作者:——樹(shù)深遇鹿

          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)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产日逼片| 国产裸身美女网站 | 久操大香蕉在线视频 | 亚洲日韩在线看 | 91人妻无码成人精品一区91 |