欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

node強(qiáng)緩存和協(xié)商緩存實(shí)戰(zhàn)示例

 更新時(shí)間:2022年07月04日 16:35:55   作者:前端好好玩  
這篇文章主要為大家介紹了node強(qiáng)緩存和協(xié)商緩存實(shí)戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

瀏覽器緩存是性能優(yōu)化非常重要的一個(gè)方案,合理地使用緩存可以提高用戶體驗(yàn),還能節(jié)省服務(wù)器的開銷。掌握好緩存的原理和并合理地使用無論對(duì)前端還是運(yùn)維都是相當(dāng)重要的。

什么是瀏覽器緩存

瀏覽器緩存(http 緩存) 是指瀏覽器在本地磁盤對(duì)用戶最近請(qǐng)求過的文檔進(jìn)行存儲(chǔ),當(dāng)訪問者再次訪問同一頁面時(shí),瀏覽器就可以直接從本地磁盤加載文檔。

優(yōu)點(diǎn)

減少了冗余的數(shù)據(jù)傳輸,節(jié)省帶寬,減少服務(wù)器壓力

加快了客戶端加載速度,提升用戶體驗(yàn)。

強(qiáng)緩存

強(qiáng)緩存不會(huì)向服務(wù)器發(fā)送請(qǐng)求,而是直接從緩存中讀取資源,強(qiáng)緩存可以通過設(shè)置兩種 HTTP Header 實(shí)現(xiàn):Expires 和 Cache-Control,這兩個(gè)頭部分別是HTTP1.0和HTTP1.1的實(shí)現(xiàn)。

Expires

Expires是HTTP1.0提出的一個(gè)表示資源過期時(shí)間的header,它描述的是一個(gè)絕對(duì)時(shí)間,由服務(wù)器返回。

Expires 受限于本地時(shí)間,如果修改了本地時(shí)間,就會(huì)造成緩存失效。

Cache-Control

Cache-Control 出現(xiàn)于 HTTP/1.1,常見字段是max-age,單位是秒,很多web服務(wù)器都有默認(rèn)配置,優(yōu)先級(jí)高于Expires,表示的是相對(duì)時(shí)間。

例如Cache-Control:max-age=3600 代表資源的有效期是 3600 秒。取的是響應(yīng)頭中的 Date,請(qǐng)求發(fā)送的時(shí)間,表示當(dāng)前資源在 Date ~ Date +3600s 這段時(shí)間里都是有效的。Cache-Control 還擁有多個(gè)值:

  • no-cache 不直接使用緩存,也就是跳過強(qiáng)緩存。
  • no-store 禁止瀏覽器緩存數(shù)據(jù),每次請(qǐng)求資源都會(huì)向服務(wù)器要完整的資源。
  • public 可以被所有用戶緩存,包括終端用戶和 CDN 等中間件代理服務(wù)器。
  • private 只允許終端用戶的瀏覽器緩存,不允許其他中間代理服務(wù)器緩存。

要注意的就是no-cache和no-store的區(qū)別,no-cache是跳過強(qiáng)緩存,還是會(huì)走協(xié)商緩存的步驟,而no-store是真正的完全不走緩存,所有資源都不會(huì)緩存在本地

協(xié)商緩存

當(dāng)瀏覽器對(duì)某個(gè)資源的請(qǐng)求沒有命中強(qiáng)緩存,就會(huì)發(fā)一個(gè)請(qǐng)求到服務(wù)器,驗(yàn)證協(xié)商緩存是否命中,如果協(xié)商緩存命中,請(qǐng)求響應(yīng)返回的http狀態(tài)為304并且會(huì)顯示一個(gè)Not Modified的字符串。

協(xié)商緩存用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】這兩對(duì)Header來管理的。

注意!!協(xié)商緩存需要配合強(qiáng)緩存使用,使用協(xié)商緩存需要先設(shè)置Cache-Control:no-cache或者pragma:no-cache來告訴瀏覽器不走強(qiáng)緩存

Last-Modified、If-Modified-Since

這兩個(gè)Header是HTTP1.0版本提出來的,兩個(gè)字段配合使用。

Last-Modified 表示本地文件最后修改日期,瀏覽器會(huì)在請(qǐng)求頭帶上If-Modified-Since(上次返回的Last-Modified的值),服務(wù)器會(huì)將這個(gè)值與資源修改的時(shí)間匹配,如果時(shí)間不一致,服務(wù)器會(huì)返回新的資源,并且將 Last-Modified 值更新,作為響應(yīng)頭返回給瀏覽器。如果時(shí)間一致,表示資源沒有更新,服務(wù)器返回 304 狀態(tài)碼,瀏覽器拿到響應(yīng)狀態(tài)碼后從本地緩存中讀取資源。

但Last-Modified有幾個(gè)問題。

  • 文件雖然被修改了,但最終的內(nèi)容沒有變化,這樣文件修改時(shí)間還是會(huì)被更新
  • 有的文件修改頻率在秒以內(nèi),這時(shí)候以秒粒度來記錄就不夠了
  • 有的服務(wù)器無法精確獲取文件的最后修改時(shí)間。

所以出現(xiàn)了ETAG。

ETag、If-None-Match

在HTTP1.1版本中,服務(wù)器通過 Etag 來設(shè)置響應(yīng)頭緩存標(biāo)識(shí)。Etag 的值由服務(wù)端生成。在第一次請(qǐng)求時(shí),服務(wù)器會(huì)將資源和 Etag 一并返回給瀏覽器,瀏覽器將兩者緩存到本地緩存數(shù)據(jù)庫。在第二次請(qǐng)求時(shí),瀏覽器會(huì)將 Etag 信息放到 If-None-Match 請(qǐng)求頭去訪問服務(wù)器,服務(wù)器收到請(qǐng)求后,會(huì)將服務(wù)器中的文件標(biāo)識(shí)與瀏覽器發(fā)來的標(biāo)識(shí)進(jìn)行對(duì)比,如果不相同,服務(wù)器返回更新的資源和新的 Etag ,如果相同,服務(wù)器返回 304 狀態(tài)碼,瀏覽器讀取緩存。

image.png

流程總結(jié)

image.png

總結(jié)這幾個(gè)字段:

  • Cache-Control —— 請(qǐng)求服務(wù)器之前
  • Expires —— 請(qǐng)求服務(wù)器之前
  • If-None-Match (Etag) —— 請(qǐng)求服務(wù)器
  • If-Modified-Since (Last-Modified) —— 請(qǐng)求服務(wù)器

node實(shí)踐

本文用koa來做例子,因?yàn)閗oa是更輕量級(jí)的、更純凈的,本身并沒有捆綁任何中間件,相比express自帶了很多router、static等多種中間件函數(shù),koa更適合本文來做示例。

koa啟動(dòng)服務(wù)

秉著學(xué)習(xí)和更容易理解的宗旨,不使用koa-static和koa-router中間件,用koa簡(jiǎn)易實(shí)現(xiàn)web服務(wù)器來驗(yàn)證之前的結(jié)論。

創(chuàng)建項(xiàng)目

# 創(chuàng)建并進(jìn)入一個(gè)目錄并新建index.js文件
mkdir koa-cache
cd koa-cache
touch index.js

# 初始化項(xiàng)目
git init
yarn init

# 將 koa 安裝為本地依賴
yarn add koa

koa代碼

/*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')
})

啟動(dòng)服務(wù)

node index.js

這樣一個(gè)koa服務(wù)就起來了,訪問localhost:3000可以就看到hello koa。

為了方便調(diào)試,修改代碼不用重新啟動(dòng),推薦使用nodemon或者pm2啟動(dòng)服務(wù)。

原生koa實(shí)現(xiàn)簡(jiǎn)易靜態(tài)資源服務(wù)

實(shí)現(xiàn)一個(gè)靜態(tài)資源服務(wù)器關(guān)鍵點(diǎn)就是根據(jù)前端請(qǐng)求的地址來判斷請(qǐng)求的資源類型,設(shè)置返回的Content-Type,讓瀏覽器知道返回的內(nèi)容類型,瀏覽器才能決定以什么形式,什么編碼來讀取返回的內(nèi)容。

定義資源類型列表

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',
}

解析請(qǐng)求的資源類型

function parseMime(url) {
  // path.extname獲取路徑中文件的后綴名
  let extName = path.extname(url)
  extName = extName ? extName.slice(1) : 'unknown'
  return mimes[extName]
}

fs讀取文件

const parseStatic = (dir) => {
  return new Promise((resolve) => {
    resolve(fs.readFileSync(dir), 'binary')
  })
}

koa處理

app.use(async (ctx) => {
  const url = ctx.request.url
  if (url === '/') {
    // 訪問根路徑返回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))
  }
})

這樣基本也就完成了一個(gè)簡(jiǎn)單的靜態(tài)資源服務(wù)器。然后在根目錄下新建一個(gè)html文件和static目錄,并在static下放一些文件。這時(shí)候的目錄應(yīng)該是這樣的:

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

這時(shí)候就可以通過localhost:3000/static訪問具體的資源文件了。

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">測(cè)試css文件</div>
   <img src="/static/image/soldier.png" alt="" />
 </body>
</html>

css/color.css

#app {
  color: blue;
}

這時(shí)候打開localhost:3000,就能看到如下效果:

image.png

到這里基本的環(huán)境就都搭好了。接下來進(jìn)入驗(yàn)證階段。

強(qiáng)緩存驗(yàn)證

在沒有任何配置之前,可以看下network:

image.png

這時(shí)候無論是首次還是第幾次,都會(huì)向服務(wù)器請(qǐng)求資源。

注意?。?!在開始實(shí)驗(yàn)之前要把network面板的Disable cache勾選去掉,這個(gè)選項(xiàng)表示禁用瀏覽器緩存,瀏覽器請(qǐng)求會(huì)帶上Cache-Control: no-cache和Pragma: no-cache頭部信息,這時(shí)候所有的請(qǐng)求都不會(huì)走緩存

image.png

設(shè)置Expire

修改index.js中的app.use代碼段。

app.use(async (ctx) => {
  const url = ctx.request.url
  if (url === '/') {
    // 訪問根路徑返回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))
    // 設(shè)置過期時(shí)間在30000毫秒,也就是30秒后
    ctx.set('Expires', new Date(Date.now() + 30000))
    ctx.body = await parseStatic(filePath)
  }
})

用ctx.set(‘Expires’, new Date(Date.now() + 30000)),設(shè)置過期時(shí)間為當(dāng)期時(shí)間的30000毫秒,也就是30秒后(后面的設(shè)置頭部信息都是這里修改)。

再訪問下localhost:3000,可以看到多了Expires這個(gè)Header。

image.png

后面在30秒之內(nèi)訪問都可以看到network的Size,css文件顯示的是disk cache,而image資源顯示的是from memory cache。這時(shí)候?yàn)g覽器是直接讀的瀏覽器緩存,并沒有請(qǐng)求服務(wù)器,可以嘗試把css和圖片文件改名稱或者刪除驗(yàn)證下,頁面顯示正常,說明之前的結(jié)論是沒錯(cuò)的。

image.png

Cache-Control

ctx.set(‘Cache-Control’, ‘max-age=300’)設(shè)置300秒有效期,驗(yàn)證方式同上。

協(xié)商緩存驗(yàn)證

Last-Modified,If-Modified-Since

HTTP1.0協(xié)商緩存關(guān)鍵點(diǎn)就是根據(jù)客戶端請(qǐng)求帶的ifModifiedSince字段的時(shí)間和請(qǐng)求的資源對(duì)應(yīng)的修改時(shí)間來判斷資源是否有更新。

首先設(shè)置Cache-Control: no-cache, 使客戶端不走強(qiáng)緩存,再判斷客戶端請(qǐng)求是否有帶ifModifiedSince字段,沒有就設(shè)置Last-Modified字段,并返回資源文件。如果有就用fs.stat讀取資源文件的修改時(shí)間,并進(jìn)行對(duì)比,如果時(shí)間一樣,則返回狀態(tài)碼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的關(guān)鍵點(diǎn)在于計(jì)算資源文件的唯一性,這里使用nodejs內(nèi)置的crypto模塊來計(jì)算文件的hash值,并用十六進(jìn)制的字符串表示。cypto的用法可以看nodejs的官網(wǎng)。

crpto不僅支持字符串的加密,還支持傳入buffer加密,作為nodejs的內(nèi)置模塊,在這里用來計(jì)算文件的唯一標(biāo)識(shí)再合適不過。

    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
    }

效果如下圖,第二次請(qǐng)求瀏覽器會(huì)帶上If-None-Match,服務(wù)器計(jì)算文件的hash值再次比較,相同則返回304,不同再返回新的文件。而如果修改了文件,文件的hash值也就變了,這時(shí)候兩個(gè)hash不匹配,服務(wù)器則返回新的文件并帶上新文件的hash值作為etag。

image.png

小結(jié)

通過以上代碼實(shí)踐了每個(gè)緩存字段的效果,代碼僅作為演示,生產(chǎn)的靜態(tài)資源服務(wù)器會(huì)更加復(fù)雜,例如etag不會(huì)每次都重新獲取文件來計(jì)算文件的hash值,這樣太費(fèi)性能,一般都會(huì)有響應(yīng)的緩存機(jī)制,比如對(duì)資源的 last-modified 和 etag 值建立索引緩存。

總結(jié)

通常web服務(wù)器都有默認(rèn)的緩存配置,具體的實(shí)現(xiàn)可能也不大相同,像nginx、tomcat、express等web服務(wù)器都有相應(yīng)的源碼,有興趣的可以去閱讀學(xué)習(xí)。

合理的使用強(qiáng)緩存和協(xié)商緩存具體需要看項(xiàng)目的使用場(chǎng)景和需求。像目前常見的單頁面應(yīng)用,因?yàn)橥ǔ4虬际切律蒱tml與相應(yīng)的靜態(tài)資源依賴,所以可以對(duì)html文件配置協(xié)商緩存,而打包生成的依賴,例如js、css這些文件可以使用強(qiáng)緩存?;蛘咧粚?duì)第三方庫使用強(qiáng)緩存,因?yàn)榈谌綆焱ǔ0姹靖螺^慢,可以鎖定版本。

node示例完整代碼 https://github.com/chen-junyi/code/blob/main/node/cache/koa2.js

以上就是node強(qiáng)緩存和協(xié)商緩存實(shí)戰(zhàn)示例的詳細(xì)內(nèi)容,更多關(guān)于node強(qiáng)緩存協(xié)商緩存的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Node.js視頻流應(yīng)用創(chuàng)建之后端的全過程

    Node.js視頻流應(yīng)用創(chuàng)建之后端的全過程

    這篇文章主要給大家介紹了關(guān)于創(chuàng)建Node.js視頻流應(yīng)用之后端的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-03-03
  • 深入Node TCP模塊的理解

    深入Node TCP模塊的理解

    這篇文章主要介紹了深入Node TCP模塊的理解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • nodejs?實(shí)現(xiàn)簡(jiǎn)單的文件上傳功能(示例詳解)

    nodejs?實(shí)現(xiàn)簡(jiǎn)單的文件上傳功能(示例詳解)

    這篇文章主要介紹了nodejs?實(shí)現(xiàn)簡(jiǎn)單的文件上傳功能,文件上傳方式分為三種,本文通過實(shí)例代碼給大家詳細(xì)介紹,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • 實(shí)戰(zhàn)node靜態(tài)文件服務(wù)器的示例代碼

    實(shí)戰(zhàn)node靜態(tài)文件服務(wù)器的示例代碼

    本篇文章主要介紹了實(shí)戰(zhàn)node靜態(tài)文件服務(wù)器的示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03
  • node異步方法的異步調(diào)用與同步調(diào)用實(shí)現(xiàn)方法示例

    node異步方法的異步調(diào)用與同步調(diào)用實(shí)現(xiàn)方法示例

    這篇文章主要介紹了node異步方法的異步調(diào)用與同步調(diào)用實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了node.js異步操作類的封裝以及同步、異步兩種調(diào)用方式,需要的朋友可以參考下
    2023-05-05
  • node運(yùn)行js獲得輸出的三種方式示例詳解

    node運(yùn)行js獲得輸出的三種方式示例詳解

    這篇文章主要介紹了node運(yùn)行js獲得輸出的三種方式,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • koa+jwt實(shí)現(xiàn)token驗(yàn)證與刷新功能

    koa+jwt實(shí)現(xiàn)token驗(yàn)證與刷新功能

    這篇文章主要介紹了koa+jwt實(shí)現(xiàn)token驗(yàn)證與刷新功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-05-05
  • nodejs遍歷文件夾下并操作HTML/CSS/JS/PNG/JPG的方法

    nodejs遍歷文件夾下并操作HTML/CSS/JS/PNG/JPG的方法

    這篇文章主要介紹了nodejs遍歷文件夾下并操作HTML/CSS/JS/PNG/JPG的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-11-11
  • Node.js簡(jiǎn)單入門前傳

    Node.js簡(jiǎn)單入門前傳

    Node.js 是一個(gè)基于Chrome JavaScript 運(yùn)行時(shí)建立的一個(gè)平臺(tái)。接下來通過本文給大家分享node.js 入門前傳,感興趣的朋友一起看看吧
    2017-08-08
  • 詳解兩個(gè)Node.js進(jìn)程是如何通信

    詳解兩個(gè)Node.js進(jìn)程是如何通信

    進(jìn)程間通信是是Node.js的一個(gè)十分重要的部分,這篇文章主要給大家介紹了關(guān)于兩個(gè)Node.js進(jìn)程是如何通信的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-10-10

最新評(píng)論