iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >HTTP中ETag语法及使用方法是什么
  • 556
分享到

HTTP中ETag语法及使用方法是什么

2023-07-05 09:07:24 556人浏览 安东尼
摘要

这篇文章主要介绍“Http中ETag语法及使用方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“HTTP中ETag语法及使用方法是什么”文章能帮助大家解决问题。一、ETag 简介1.1 ETa

这篇文章主要介绍“Http中ETag语法及使用方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“HTTP中ETag语法及使用方法是什么”文章能帮助大家解决问题。

    一、ETag 简介

    1.1 ETag 是什么

    ETag(Entity Tag)是万维网协议 HTTP 的一部分。它是 HTTP 协议提供的若干机制中的一种 WEB 缓存验证机制,并且允许客户端进行缓存协商。这使得缓存变得更加高效,而且节省带宽。如果资源的内容没有发生改变,Web 服务器就不需要发送一个完整的响应。

    1.2 ETag 的作用

    ETag 是一个不透明的标识符,由 Web 服务器根据 URL 上的资源的特定版本而指定。如果 URL 上的资源内容改变,一个新的不一样的 ETag 就会被生成。ETag 可以看成是资源的指纹,它们能够被快速地比较,以确定两个版本的资源是否相同。
    需要注意的是 ETag 的比较只对同一个 URL 有意义 —— 不同 URL 上资源的 ETag 值可能相同也可能不同。

    1.3 ETag 的语法

    ETag: W/"<etag_value>"ETag: "<etag_value>"
    • W/(可选):'W/'(大小写敏感) 表示使用弱验证器。弱验证器很容易生成,但不利于比较。强验证器是比较的理想选择,但很难有效地生成。相同资源的两个弱 Etag 值可能语义等同,但不是每个字节都相同。

    • "<etag_value>":实体标签唯一地表示所请求的资源。它们是位于双引号之间的 ASCII 字符串(如 “2c-1799c10ab70” )。没有明确指定生成 ETag 值的方法。通常是使用内容的散列、最后修改时间戳的哈希值或简单地使用版本号。比如,MDN 使用 wiki 内容的十六进制数字的哈希值。

    1.4 ETag 的使用

    在大多数场景下,当一个 URL 被请求,Web 服务器会返回资源和其相应的 ETag 值,它会被放置在 HTTP 响应头的 ETag 字段中:

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

    然后,客户端可以决定是否缓存这个资源和它的 ETag。以后,如果客户端想再次请求相同的 URL,将会发送一个包含已保存的 ETag 和 If-None-Match 字段的请求。

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

    客户端请求之后,服务器可能会比较客户端的 ETag 和当前版本资源的 ETag。如果 ETag 值匹配,这就意味着资源没有改变,服务器便会发送回一个极短的响应,包含 HTTP “304 未修改” 的状态。304 状态码告诉客户端,它的缓存版本是最新的,可以直接使用它。

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

    二、ETag 实战

    2.1 创建 Koa 服务器

    了解完 ETag 相关知识后,基于 koakoa-conditional-getkoa-etagkoa-static 这些库来介绍一下,在实际项目中如何利用 ETag 响应头和 If-None-Match 请求头实现资源的缓存控制。

    // server.jsconst 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()); // 使用条件请求中间件app.use(etag()); // 使用etag中间件app.use( // 使用静态资源中间件  serve(path.join(__dirname, "/public"), {    maxage: 10 * 1000, // 设置缓存存储的最大周期,单位为秒  }));app.listen(3000, () => {  console.log("app starting at port 3000");});

    在以上代码中,使用了 koa-static 中间件来处理静态资源,这些资源被保存在 public 目录下。在该目录下,创建了 index.html 和 index.js 两个资源文件,文件中的内容分别如下所示:

    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>    <h4>ETag 使用示例</h4></body></html>
    2.1.2 public/index.js
    console.log("大家好");

    在启动完服务器之后,打开 Chrome 开发工具并切换到 Network 标签栏,然后在浏览器地址栏输入 http://localhost:3000/ 地址,接着多次访问该地址(地址栏多次回车)。下图是多次访问的结果:

    HTTP中ETag语法及使用方法是什么

    2.2 ETag 和 If-None-Match

    下面以 index.js 为例,来分析上图中与之对应的 HTTP 报文。对于 index.html 文件,感兴趣的小伙伴可以自行分析一下。接下来先来分析首次请求 index.js 文件的报文:

    2.2.1 首次请求 &mdash; 请求报文
    GET /index.js HTTP/1.1Host: localhost:3000Connection: keep-alivePragma: no-cacheCache-Control: no-cache...
    2.2.2 首次请求 &mdash; 响应报文
    HTTP/1.1 200 OKContent-Length: 44Cache-Control: max-age=10ETag: W/"2c-1799c10ab70"...

    在使用了 koa-static 和 koa-etag 中间件之后,index.js 文件首次请求的响应报文中会包含 Cache-ControlETag 的字段信息。
    Cache-Control 描述的是一个相对时间,在进行缓存命中的时候,都是利用客户端时间进行判断,所以相比较 ExpiresCache-Control 的缓存管理更有效,安全一些。

    2.2.3 10s内 &mdash; 请求报文
    GET /index.js HTTP/1.1Host: localhost:3000Connection: keep-alivePragma: no-cacheCache-Control: no-cache...
    2.2.4 10s内 &mdash; 响应信息(General)
    Request URL: http://localhost:3000/index.jsRequest Method: GETStatus Code: 200 OK (from memory cache)Remote Address: [::1]:3000Referrer Policy: strict-origin-when-cross-origin
    2.2.5 10s内 &mdash; 响应信息(Response Headers)
    Cache-Control: max-age=10Connection: keep-aliveContent-Length: 44ETag: W/"2c-1799c10ab70"

    由于设置了 index.js 资源文件的最大缓存时间为 10s,所以在 10s 内浏览器会直接从缓存中读取文件的内容。需要注意的是,此时的状态码为:Status Code: 200 OK (from memory cache)

    2.2.6 10s后 &mdash; 请求报文
    GET /index.js HTTP/1.1Host: localhost:3000Connection: keep-aliveIf-None-Match: W/"2c-1799c10ab70"Referer: http://localhost:3000/...

    因为 10s 之后,缓存已经过期了,而且在 index.js 文件首次请求的响应报文中也返回了 ETag 字段。所以此时浏览器会发起 If-None-Match 条件请求。这类请求可以用来验证缓存的有效性,省去不必要的控制手段。

    2.2.7 10s后 &mdash; 响应报文
    HTTP/1.1 304 Not ModifiedCache-Control: max-age=10ETag: W/"2c-1799c10ab70"Connection: keep-alive...

    因为文件的内容未发生改变,所以 10s 后的响应报文的状态码为 304 Not Modified。此外,响应报文中也返回了 ETag 字段。看到这里,有一些小伙伴可能会有疑惑 &mdash;&mdash; ETag 到底是如何生成的?接下来揭开 koa-etag 中间件背后的秘密。

    三、如何生成 ETag

    在前面的示例中,使用了 koa-etag 中间件来实现资源的缓存控制。其实该中间件的实现并不复杂,具体如下所示:

    // https://GitHub.com/koajs/etag/blob/master/index.jsconst 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 中间件内部会先通过 getResponseEntity 函数来获取响应实体对象,然后再调用 setETag 函数来生成 ETag。而 setETag 函数的实现很简单,在 setETag 函数内部,会通过 etag 这个第三方库来生成 ETag。

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

    etag 这个库对外提供了一个 etag 函数来创建 ETag,该函数的签名如下:

    etag(entity, [options])
    • entity:用于生成 ETag 的实体,类型支持 StringsBuffersfs.Stats。除了 fs.Stats 对象之外,默认将生成 strong ETag

    • options:配置对象,支持通过 options.weak 属性来配置生成 weak ETag。

    了解完 etag 函数的参数之后,来看一下该函数的具体实现:

    function etag (entity, options) {  if (entity == null) {    throw new TypeError('argument entity is required')  }  // 支持fs.Stats对象  // isstats 函数的判断规则:当前对象是否包含ctime、mtime、ino和size这些属性  var isStats = isstats(entity)  var weak = options && typeof options.weak === 'boolean'    ? options.weak    : isStats  // 参数校验  if (!isStats && typeof entity !== 'string' && !Buffer.isBuffer(entity)) {    throw new TypeError('argument entity must be string, Buffer, or fs.Stats')  }  // 生成ETag标签  var tag = isStats    ? stattag(entity) // 处理fs.Stats对象    : entitytag(entity)  return weak    ? 'W/' + tag    : tag}

    etag 函数内部会根据 entity 的类型,执行不同的生成逻辑。如果 entityfs.Stats 对象,则会调用 stattag 函数来创建 ETag。

    function stattag (stat) {  // mtime:Modified Time,是在写入文件时随文件内容的更改而更改,是指文件内容最后一次被修改的时间。  var mtime = stat.mtime.getTime().toString(16)  var size = stat.size.toString(16)  return '"' + size + '-' + mtime + '"'}

    而如果 entity 参数非 fs.Stats 对象,则会调用 entitytag 函数来生成 ETag。其中 entitytag 函数的具体实现如下:

    function entitytag (entity) {  if (entity.length === 0) {    return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"'  }  // 计算实体对象的哈希值  var hash = crypto    .createHash('sha1')    .update(entity, 'utf8')    .digest('base64')    .substring(0, 27)  // 计算实体对象的长度  var len = typeof entity === 'string'    ? Buffer.byteLength(entity, 'utf8')    : entity.length  return '"' + len.toString(16) + '-' + hash + '"'}

    对于非 fs.Stats 对象来说,在 entitytag 函数内部会使用 sha1 消息摘要算法来生成 hash 值并以 base64 格式输出,而实际的生成的 hash 值会取前 27 个字符。此外,由以上代码可知,最终的 ETag 将由实体的长度和哈希值两部分组成。
    需要注意的是,生成 ETag 的算法并不是固定的, 通常是使用内容的散列、最后修改时间戳的哈希值或简单地使用版本号。

    四、ETag vs Last-Modified

    其实除了 ETag 字段之外,大多数情况下,响应头中还会包含 Last-Modified 字段。它们之间的区别如下:

    • 精确度上,Etag 要优于 Last-Modified。Last-Modified 的时间单位是秒,如果某个文件在 1 秒内被改变多次,那么它们的 Last-Modified 并没有体现出来修改,但是 Etag 每次都会改变,从而确保了精度;此外,如果是负载均衡的服务器,各个服务器生成的 Last-Modified 也有可能不一致。

    • 性能上,Etag 要逊于 Last-Modified,毕竟 Last-Modified 只需要记录时间,而 ETag 需要服务器通过消息摘要算法来计算出一个hash 值。

    • 优先级上,在资源新鲜度校验时,服务器会优先考虑 Etag。即如果条件请求的请求头同时携带 If-Modified-SinceIf-None-Match 字段,则会优先判断资源的 ETag 值是否发生变化。

    关于“HTTP中ETag语法及使用方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网精选频道,小编每天都会为大家更新不同的知识点。

    --结束END--

    本文标题: HTTP中ETag语法及使用方法是什么

    本文链接: https://www.lsjlt.com/news/350930.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • HTTP中ETag语法及使用方法是什么
      这篇文章主要介绍“HTTP中ETag语法及使用方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“HTTP中ETag语法及使用方法是什么”文章能帮助大家解决问题。一、ETag 简介1.1 ETa...
      99+
      2023-07-05
    • HTTP中ETag语法及使用实战详解
      目录一、ETag 简介1.1 ETag 是什么1.2 ETag 的作用1.3 ETag 的语法1.4 ETag 的使用二、ETag 实战2.1 创建 Koa 服务器2.1.1 pub...
      99+
      2023-03-07
      HTTP ETag语法 HTTP ETag
    • Django中HTTP响应的使用方法是什么?
      Django是一种流行的Web框架,它提供了许多有用的功能,其中一个是HTTP响应。在本文中,我们将探讨Django中HTTP响应的使用方法。 HTTP响应是服务器向客户端发送的数据,用于响应客户端请求。在Django中,我们可以使用Htt...
      99+
      2023-07-07
      http 响应 django
    • PHP中常用查询语句及使用方法是什么
      这篇文章主要介绍了PHP中常用查询语句及使用方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇PHP中常用查询语句及使用方法是什么文章都会有所收获,下面我们一起来看看吧。一、SELECT语句SEL...
      99+
      2023-07-05
    • assert.h是什么及使用方法
      assert.h是C语言中的头文件,用于定义宏函数assert和宏变量NDEBUG。assert宏函数用于在程序中进行断言测试,即判...
      99+
      2023-09-14
      assert.h
    • update语法是什么及怎么使用
      UPDATE语法用于修改表中的数据。它的基本语法如下:```UPDATE table_nameSET column1 = value...
      99+
      2023-06-13
      update语法
    • systemctl用法及其语法是什么
      这期内容当中小编将会给大家带来有关systemctl用法及其语法是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。确定是否安装systemd及其版本# systemctl –version确定syste...
      99+
      2023-06-05
    • JavaScript是什么以及使用方法
      本篇文章给大家分享的是有关JavaScript是什么以及使用方法,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。 一、JavaScri...
      99+
      2024-04-02
    • Node http模块基本使用方法是什么
      这篇文章主要介绍了Node http模块基本使用方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Node http模块基本使用方法是什么文章都会有所收获,下面我们一起来看看吧。http 模块使用 Nod...
      99+
      2023-07-05
    • PHP中SQL修改语法和使用方法是什么
      本文小编为大家详细介绍“PHP中SQL修改语法和使用方法是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“PHP中SQL修改语法和使用方法是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一、语法在PHP中...
      99+
      2023-07-05
    • GO语言中HTTP打包文件的方法是什么?
      随着互联网的不断发展,文件上传和下载已经成为了我们日常生活中不可或缺的一部分。在这个过程中,HTTP协议无疑是最常用的协议之一。GO语言作为一门新兴的编程语言,对于HTTP协议的支持也非常完善,本文将介绍GO语言中HTTP打包文件的方法。...
      99+
      2023-06-24
      http 打包 文件
    • c语言中回调函数的使用方法及作用是什么
      本篇内容介绍了“c语言中回调函数的使用方法及作用是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!目录前言一、通过这节课程你能掌握以下知识...
      99+
      2023-06-20
    • c语言中break的使用方法是什么
      在C语言中,break语句用于终止循环或switch语句,并将程序控制流转移到循环或switch语句之后的下一行代码。break的使...
      99+
      2023-10-12
      c语言
    • go语言中ffmpeg使用的方法是什么
      Go语言中使用FFmpeg的方法有两种:使用CGO调用FFmpeg的C语言库,或者使用Go语言封装的FFmpeg库。 使用CGO调...
      99+
      2024-02-29
      go语言 ffmpeg
    • c语言中free的使用方法是什么
      在C语言中,free()函数用于释放之前通过malloc()、calloc()或realloc()函数动态分配的内存空间。使用方法如...
      99+
      2024-03-15
      c语言
    • C语言中getchar的使用方法是什么
      getchar()函数用于从标准输入流(stdin)读取一个字符,并返回该字符的ASCII码值。它的基本用法如下: int...
      99+
      2024-03-06
      C语言
    • sql中alter语句的使用方法是什么
      在SQL中,ALTER语句用于修改现有数据库表的结构,例如添加,删除或修改列,修改表的名称,以及修改表的约束等。 通用的ALTER语...
      99+
      2024-04-09
      sql
    • 什么是语法糖?Vue3.2中怎么使用语法糖?
      3.计算属性我们一般使用计算属性来描述依赖响应式状态的复杂逻辑。说白了就是这个计算属性的值依赖于其他响应式属性的值,依赖的属性发生变化,那么这个计算属性的值就会进行重新计算。<script setup> import { ref...
      99+
      2022-11-28
      语法糖 Vue.js
    • JS中Promise的使用及封装方法是什么
      这篇文章主要介绍了JS中Promise的使用及封装方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JS中Promise的使用及封装方法是什么文章都会有所收获,下面我们一起来看看吧。Promise 是什么...
      99+
      2023-07-05
    • c语言中/是什么意思及用法
      c 语言中的除法运算符是 /,用于计算两个操作数的商。它支持整数和浮点数除法,优先级高于加减法但低于乘除法。除以 0 会产生运行时错误。整数除法舍弃小数部分,而浮点数除法返回浮点数商。 ...
      99+
      2024-04-13
      c语言
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作