最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

HTTP中ETag語(yǔ)法及使用實(shí)戰(zhàn)詳解

 更新時(shí)間:2023年03月07日 09:00:12   作者:睡醒想錢錢  
這篇文章主要為大家介紹了HTTP中ETag語(yǔ)法及使用實(shí)戰(zhàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

一、ETag 簡(jiǎn)介

1.1 ETag 是什么

ETag(Entity Tag)是萬(wàn)維網(wǎng)協(xié)議 HTTP 的一部分。它是 HTTP 協(xié)議提供的若干機(jī)制中的一種 Web 緩存驗(yàn)證機(jī)制,并且允許客戶端進(jìn)行緩存協(xié)商。這使得緩存變得更加高效,而且節(jié)省帶寬。如果資源的內(nèi)容沒(méi)有發(fā)生改變,Web 服務(wù)器就不需要發(fā)送一個(gè)完整的響應(yīng)。

1.2 ETag 的作用

ETag 是一個(gè)不透明的標(biāo)識(shí)符,由 Web 服務(wù)器根據(jù) URL 上的資源的特定版本而指定。如果 URL 上的資源內(nèi)容改變,一個(gè)新的不一樣的 ETag 就會(huì)被生成。ETag 可以看成是資源的指紋,它們能夠被快速地比較,以確定兩個(gè)版本的資源是否相同。
需要注意的是 ETag 的比較只對(duì)同一個(gè) URL 有意義 —— 不同 URL 上資源的 ETag 值可能相同也可能不同。

1.3 ETag 的語(yǔ)法

ETag: W/"<etag_value>"
ETag: "<etag_value>"
  • W/(可選):'W/'(大小寫敏感) 表示使用弱驗(yàn)證器。弱驗(yàn)證器很容易生成,但不利于比較。強(qiáng)驗(yàn)證器是比較的理想選擇,但很難有效地生成。相同資源的兩個(gè)弱 Etag 值可能語(yǔ)義等同,但不是每個(gè)字節(jié)都相同。
  • "<etag_value>":實(shí)體標(biāo)簽唯一地表示所請(qǐng)求的資源。它們是位于雙引號(hào)之間的 ASCII 字符串(如 “2c-1799c10ab70” )。沒(méi)有明確指定生成 ETag 值的方法。通常是使用內(nèi)容的散列、最后修改時(shí)間戳的哈希值或簡(jiǎn)單地使用版本號(hào)。比如,MDN 使用 wiki 內(nèi)容的十六進(jìn)制數(shù)字的哈希值。

1.4 ETag 的使用

在大多數(shù)場(chǎng)景下,當(dāng)一個(gè) URL 被請(qǐng)求,Web 服務(wù)器會(huì)返回資源和其相應(yīng)的 ETag 值,它會(huì)被放置在 HTTP 響應(yīng)頭的 ETag 字段中:

HTTP/1.1 200 OK
Content-Length: 44
Cache-Control: max-age=10
Content-Type: application/javascript; charset=utf-8
ETag: W/"2c-1799c10ab70"

然后,客戶端可以決定是否緩存這個(gè)資源和它的 ETag。以后,如果客戶端想再次請(qǐng)求相同的 URL,將會(huì)發(fā)送一個(gè)包含已保存的 ETag 和 If-None-Match 字段的請(qǐng)求。

GET /index.js HTTP/1.1
Host: localhost:3000
Connection: keep-alive
If-None-Match: W/"2c-1799c10ab70"

客戶端請(qǐng)求之后,服務(wù)器可能會(huì)比較客戶端的 ETag 和當(dāng)前版本資源的 ETag。如果 ETag 值匹配,這就意味著資源沒(méi)有改變,服務(wù)器便會(huì)發(fā)送回一個(gè)極短的響應(yīng),包含 HTTP “304 未修改” 的狀態(tài)。304 狀態(tài)碼告訴客戶端,它的緩存版本是最新的,可以直接使用它。

HTTP/1.1 304 Not Modified
Cache-Control: max-age=10
ETag: W/"2c-1799c10ab70"
Connection: keep-alive

二、ETag 實(shí)戰(zhàn)

2.1 創(chuàng)建 Koa 服務(wù)器

了解完 ETag 相關(guān)知識(shí)后,基于 koa、koa-conditional-get、koa-etagkoa-static 這些庫(kù)來(lái)介紹一下,在實(shí)際項(xiàng)目中如何利用 ETag 響應(yīng)頭和 If-None-Match 請(qǐng)求頭實(shí)現(xiàn)資源的緩存控制。

// server.js
const Koa = require("koa");
const path = require("path");
const serve = require("koa-static");
const etag = require("koa-etag");
const conditional = require("koa-conditional-get");
const app = new Koa();
app.use(conditional()); // 使用條件請(qǐng)求中間件
app.use(etag()); // 使用etag中間件
app.use( // 使用靜態(tài)資源中間件
  serve(path.join(__dirname, "/public"), {
    maxage: 10 * 1000, // 設(shè)置緩存存儲(chǔ)的最大周期,單位為秒
  })
);
app.listen(3000, () => {
  console.log("app starting at port 3000");
});

在以上代碼中,使用了 koa-static 中間件來(lái)處理靜態(tài)資源,這些資源被保存在 public 目錄下。在該目錄下,創(chuàng)建了 index.html 和 index.js 兩個(gè)資源文件,文件中的內(nèi)容分別如下所示:

2.1.1 public/index.html

<!DOCTYPE html>
<html lang="zh-cn">
<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>ETag 使用示例</title>
    <script src="/index.js"></script>
</head>
<body>
    <h3>ETag 使用示例</h3>
</body>
</html>

2.1.2 public/index.js

console.log("大家好");

在啟動(dòng)完服務(wù)器之后,打開(kāi) Chrome 開(kāi)發(fā)者工具并切換到 Network 標(biāo)簽欄,然后在瀏覽器地址欄輸入 http://localhost:3000/ 地址,接著多次訪問(wèn)該地址(地址欄多次回車)。下圖是多次訪問(wèn)的結(jié)果:

2.2 ETag 和 If-None-Match

下面以 index.js 為例,來(lái)分析上圖中與之對(duì)應(yīng)的 HTTP 報(bào)文。對(duì)于 index.html 文件,感興趣的小伙伴可以自行分析一下。接下來(lái)先來(lái)分析首次請(qǐng)求 index.js 文件的報(bào)文:

2.2.1 首次請(qǐng)求 — 請(qǐng)求報(bào)文

GET /index.js HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
...

2.2.2 首次請(qǐng)求 — 響應(yīng)報(bào)文

HTTP/1.1 200 OK
Content-Length: 44
Cache-Control: max-age=10
ETag: W/"2c-1799c10ab70"
...

在使用了 koa-static 和 koa-etag 中間件之后,index.js 文件首次請(qǐng)求的響應(yīng)報(bào)文中會(huì)包含 Cache-ControlETag 的字段信息。
Cache-Control 描述的是一個(gè)相對(duì)時(shí)間,在進(jìn)行緩存命中的時(shí)候,都是利用客戶端時(shí)間進(jìn)行判斷,所以相比較 Expires,Cache-Control 的緩存管理更有效,安全一些。

2.2.3 10s內(nèi) — 請(qǐng)求報(bào)文

GET /index.js HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
...

2.2.4 10s內(nèi) — 響應(yīng)信息(General)

Request URL: http://localhost:3000/index.js
Request Method: GET
Status Code: 200 OK (from memory cache)
Remote Address: [::1]:3000
Referrer Policy: strict-origin-when-cross-origin

2.2.5 10s內(nèi) — 響應(yīng)信息(Response Headers)

Cache-Control: max-age=10
Connection: keep-alive
Content-Length: 44
ETag: W/"2c-1799c10ab70"

由于設(shè)置了 index.js 資源文件的最大緩存時(shí)間為 10s,所以在 10s 內(nèi)瀏覽器會(huì)直接從緩存中讀取文件的內(nèi)容。需要注意的是,此時(shí)的狀態(tài)碼為:Status Code: 200 OK (from memory cache)。

2.2.6 10s后 — 請(qǐng)求報(bào)文

GET /index.js HTTP/1.1
Host: localhost:3000
Connection: keep-alive
If-None-Match: W/"2c-1799c10ab70"
Referer: http://localhost:3000/
...

因?yàn)?10s 之后,緩存已經(jīng)過(guò)期了,而且在 index.js 文件首次請(qǐng)求的響應(yīng)報(bào)文中也返回了 ETag 字段。所以此時(shí)瀏覽器會(huì)發(fā)起 If-None-Match 條件請(qǐng)求。這類請(qǐng)求可以用來(lái)驗(yàn)證緩存的有效性,省去不必要的控制手段。

2.2.7 10s后 — 響應(yīng)報(bào)文

HTTP/1.1 304 Not Modified
Cache-Control: max-age=10
ETag: W/"2c-1799c10ab70"
Connection: keep-alive
...

因?yàn)槲募膬?nèi)容未發(fā)生改變,所以 10s 后的響應(yīng)報(bào)文的狀態(tài)碼為 304 Not Modified。此外,響應(yīng)報(bào)文中也返回了 ETag 字段。看到這里,有一些小伙伴可能會(huì)有疑惑 —— ETag 到底是如何生成的?接下來(lái)揭開(kāi) koa-etag 中間件背后的秘密。

三、如何生成 ETag

在前面的示例中,使用了 koa-etag 中間件來(lái)實(shí)現(xiàn)資源的緩存控制。其實(shí)該中間件的實(shí)現(xiàn)并不復(fù)雜,具體如下所示:

// https://github.com/koajs/etag/blob/master/index.js
const calculate = require('etag');
// 省略部分代碼
module.exports = function etag (options) {
  return async function etag (ctx, next) {
    await next()
    const entity = await getResponseEntity(ctx)
    setEtag(ctx, entity, options)
  }
}

由以上代碼可知,在 koa-etag 中間件內(nèi)部會(huì)先通過(guò) getResponseEntity 函數(shù)來(lái)獲取響應(yīng)實(shí)體對(duì)象,然后再調(diào)用 setETag 函數(shù)來(lái)生成 ETag。而 setETag 函數(shù)的實(shí)現(xiàn)很簡(jiǎn)單,在 setETag 函數(shù)內(nèi)部,會(huì)通過(guò) etag 這個(gè)第三方庫(kù)來(lái)生成 ETag。

// https://github.com/koajs/etag/blob/master/index.js
function setEtag (ctx, entity, options) {
  if (!entity) return
  ctx.response.etag = calculate(entity, options)
}

etag 這個(gè)庫(kù)對(duì)外提供了一個(gè) etag 函數(shù)來(lái)創(chuàng)建 ETag,該函數(shù)的簽名如下:

etag(entity, [options])
  • entity:用于生成 ETag 的實(shí)體,類型支持 Strings,Buffersfs.Stats。除了 fs.Stats 對(duì)象之外,默認(rèn)將生成 strong ETag
  • options:配置對(duì)象,支持通過(guò) options.weak 屬性來(lái)配置生成 weak ETag。

了解完 etag 函數(shù)的參數(shù)之后,來(lái)看一下該函數(shù)的具體實(shí)現(xiàn):

function etag (entity, options) {
  if (entity == null) {
    throw new TypeError('argument entity is required')
  }
  // 支持fs.Stats對(duì)象
  // isstats 函數(shù)的判斷規(guī)則:當(dāng)前對(duì)象是否包含ctime、mtime、ino和size這些屬性
  var isStats = isstats(entity)
  var weak = options && typeof options.weak === 'boolean'
    ? options.weak
    : isStats
  // 參數(shù)校驗(yàn)
  if (!isStats && typeof entity !== 'string' && !Buffer.isBuffer(entity)) {
    throw new TypeError('argument entity must be string, Buffer, or fs.Stats')
  }
  // 生成ETag標(biāo)簽
  var tag = isStats
    ? stattag(entity) // 處理fs.Stats對(duì)象
    : entitytag(entity)
  return weak
    ? 'W/' + tag
    : tag
}

etag 函數(shù)內(nèi)部會(huì)根據(jù) entity 的類型,執(zhí)行不同的生成邏輯。如果 entityfs.Stats 對(duì)象,則會(huì)調(diào)用 stattag 函數(shù)來(lái)創(chuàng)建 ETag。

function stattag (stat) {
  // mtime:Modified Time,是在寫入文件時(shí)隨文件內(nèi)容的更改而更改,是指文件內(nèi)容最后一次被修改的時(shí)間。
  var mtime = stat.mtime.getTime().toString(16)
  var size = stat.size.toString(16)
  return '"' + size + '-' + mtime + '"'
}

而如果 entity 參數(shù)非 fs.Stats 對(duì)象,則會(huì)調(diào)用 entitytag 函數(shù)來(lái)生成 ETag。其中 entitytag 函數(shù)的具體實(shí)現(xiàn)如下:

function entitytag (entity) {
  if (entity.length === 0) {
    return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"'
  }
  // 計(jì)算實(shí)體對(duì)象的哈希值
  var hash = crypto
    .createHash('sha1')
    .update(entity, 'utf8')
    .digest('base64')
    .substring(0, 27)
  // 計(jì)算實(shí)體對(duì)象的長(zhǎng)度
  var len = typeof entity === 'string'
    ? Buffer.byteLength(entity, 'utf8')
    : entity.length
  return '"' + len.toString(16) + '-' + hash + '"'
}

對(duì)于非 fs.Stats 對(duì)象來(lái)說(shuō),在 entitytag 函數(shù)內(nèi)部會(huì)使用 sha1 消息摘要算法來(lái)生成 hash 值并以 base64 格式輸出,而實(shí)際的生成的 hash 值會(huì)取前 27 個(gè)字符。此外,由以上代碼可知,最終的 ETag 將由實(shí)體的長(zhǎng)度和哈希值兩部分組成。
需要注意的是,生成 ETag 的算法并不是固定的, 通常是使用內(nèi)容的散列、最后修改時(shí)間戳的哈希值或簡(jiǎn)單地使用版本號(hào)。

四、ETag vs Last-Modified

其實(shí)除了 ETag 字段之外,大多數(shù)情況下,響應(yīng)頭中還會(huì)包含 Last-Modified 字段。它們之間的區(qū)別如下:

  • 精確度上,Etag 要優(yōu)于 Last-Modified。Last-Modified 的時(shí)間單位是秒,如果某個(gè)文件在 1 秒內(nèi)被改變多次,那么它們的 Last-Modified 并沒(méi)有體現(xiàn)出來(lái)修改,但是 Etag 每次都會(huì)改變,從而確保了精度;此外,如果是負(fù)載均衡的服務(wù)器,各個(gè)服務(wù)器生成的 Last-Modified 也有可能不一致。
  • 性能上,Etag 要遜于 Last-Modified,畢竟 Last-Modified 只需要記錄時(shí)間,而 ETag 需要服務(wù)器通過(guò)消息摘要算法來(lái)計(jì)算出一個(gè)hash 值。
  • 優(yōu)先級(jí)上,在資源新鮮度校驗(yàn)時(shí),服務(wù)器會(huì)優(yōu)先考慮 Etag。即如果條件請(qǐng)求的請(qǐng)求頭同時(shí)攜帶 If-Modified-SinceIf-None-Match 字段,則會(huì)優(yōu)先判斷資源的 ETag 值是否發(fā)生變化。

以上就是HTTP中ETag語(yǔ)法及使用實(shí)戰(zhàn)詳解的詳細(xì)內(nèi)容,更多關(guān)于HTTP ETag語(yǔ)法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • chrome開(kāi)發(fā)者助手插件v2.10發(fā)布提升開(kāi)發(fā)效率不再只是口號(hào)

    chrome開(kāi)發(fā)者助手插件v2.10發(fā)布提升開(kāi)發(fā)效率不再只是口號(hào)

    這篇文章主要介紹了chrome開(kāi)發(fā)者助手插件v2.10發(fā)布提升開(kāi)發(fā)效率不再只是口號(hào),這個(gè)版本重點(diǎn)提升了常用工具的使用效率,需要的朋友可以參考下
    2021-03-03
  • TCP 四種定時(shí)器(重傳定時(shí)器,堅(jiān)持計(jì)時(shí)器,?;疃〞r(shí)器,時(shí)間等待計(jì)時(shí)器)

    TCP 四種定時(shí)器(重傳定時(shí)器,堅(jiān)持計(jì)時(shí)器,?;疃〞r(shí)器,時(shí)間等待計(jì)時(shí)器)

    這篇文章主要介紹了TCP 四種定時(shí)器,重傳定時(shí)器,堅(jiān)持計(jì)時(shí)器,?;疃〞r(shí)器,時(shí)間等待計(jì)時(shí)器的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • 詳解基于深度學(xué)習(xí)的兩種信源信道聯(lián)合編碼

    詳解基于深度學(xué)習(xí)的兩種信源信道聯(lián)合編碼

    信源編碼是一個(gè)數(shù)據(jù)壓縮的過(guò)程,其目的是盡可能地將信源中的冗余度去掉;而信道編碼則是一個(gè)增加冗余的過(guò)程,通過(guò)適當(dāng)加入冗余度來(lái)達(dá)到抵抗信道噪聲,保護(hù)傳輸數(shù)據(jù)的目的。
    2021-05-05
  • 詳解提升場(chǎng)景文本識(shí)別中的語(yǔ)言模型

    詳解提升場(chǎng)景文本識(shí)別中的語(yǔ)言模型

    語(yǔ)言模型即根據(jù)當(dāng)前語(yǔ)境的上下文推斷當(dāng)前句子的意思。文本圖像中包含兩層信息:視覺(jué)紋理信息和語(yǔ)言信息。由于單純根據(jù)視覺(jué)紋理信息進(jìn)行文字識(shí)別缺少了對(duì)上下文的字符語(yǔ)義信息的挖掘,時(shí)常會(huì)導(dǎo)致錯(cuò)誤的文本識(shí)別結(jié)果(之后會(huì)詳細(xì)說(shuō)明)。
    2021-05-05
  • 密碼哈希函數(shù) Bcrypt的最大密碼長(zhǎng)度限制詳解

    密碼哈希函數(shù) Bcrypt的最大密碼長(zhǎng)度限制詳解

    這篇文章主要介紹了密碼哈希函數(shù) Bcrypt的最大密碼長(zhǎng)度限制詳解的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • 如何理解軟件系統(tǒng)的高并發(fā)

    如何理解軟件系統(tǒng)的高并發(fā)

    本文介紹高并發(fā)系統(tǒng)的度量指標(biāo),講述高并發(fā)系統(tǒng)的設(shè)計(jì)思路,再梳理高并發(fā)的關(guān)鍵技術(shù),最后結(jié)合作者的經(jīng)驗(yàn)做一些延伸探討。
    2021-05-05
  • 在VScode上使用latex編輯pdf的方法

    在VScode上使用latex編輯pdf的方法

    這篇文章主要介紹了在VScode上使用latex編輯pdf的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • 聊聊自學(xué),那些讓你事半功倍的自學(xué)資源(干貨分享)

    聊聊自學(xué),那些讓你事半功倍的自學(xué)資源(干貨分享)

    B站是一個(gè)學(xué)習(xí)網(wǎng)站。一入B站深似海,從此游戲是路人。B站雖然視頻資源多,但是內(nèi)容也是五花八門、參差不齊,本文給大家收集了關(guān)于學(xué)習(xí)計(jì)算機(jī)編程的視頻,這里有我曾經(jīng)的入門視頻,也有跟朋友交流獲得的,特此篩選了下面這些視頻,分享給大家
    2021-04-04
  • 初步了解代理和負(fù)載均衡

    初步了解代理和負(fù)載均衡

    本文主要初步帶你了解代理和負(fù)載均衡的知識(shí),文中對(duì)正向、反向代理以及反向代理與負(fù)載均衡的關(guān)系等做了詳細(xì)講解,感興趣的朋友可以參考一下這篇文章
    2021-09-09
  • 匯編語(yǔ)言超濃縮教程

    匯編語(yǔ)言超濃縮教程

    對(duì)初學(xué)者而言,匯編的許多命令太復(fù)雜,往往學(xué)習(xí)很長(zhǎng)時(shí)間也寫不出一個(gè)漂漂亮亮的程序,以致妨礙了我們學(xué)習(xí)匯編的興趣,不少人就此放棄
    2013-05-05

最新評(píng)論

莒南县| 汉源县| 凌海市| 嫩江县| 临汾市| 甘孜| 宾阳县| 邯郸县| 云安县| 桃园市| 桦川县| 香港 | 寿光市| 五原县| 嘉祥县| 获嘉县| 晋宁县| 大足县| 濮阳市| 诏安县| 白沙| 松潘县| 建始县| 双峰县| 喀喇沁旗| 剑阁县| 周口市| 天全县| 阿拉尔市| 广东省| 通河县| 田阳县| 班戈县| 海兴县| 二手房| 东光县| 岳西县| 长春市| 西青区| 嘉黎县| 兴业县|