美文网首页
[转载] 使用 HTTP 缓存:Etag, Last-Modif

[转载] 使用 HTTP 缓存:Etag, Last-Modif

作者: zhimin_ | 来源:发表于2021-08-31 13:48 被阅读0次

原文链接:https://harttle.land/2017/04/04/using-http-cache.html

整个 Web 系统架构在 HTTP 协议 之上, 利用 HTTP 的缓存机制不仅可以极大地减少服务器负载, 更重要的是加速页面的载入,以及减少用户的流量消耗。 快速到达和易于访问是 Web 与生俱来的特性, 其缓存机制也早已被服务器和浏览器厂商广泛地实现, 我们作为 Web 内容的作者何乐而不为呢?

Web 服务器(比如 Tomcat、Apache、Virgo)或服务器端框架(比如 Django、Express.js) 都会实现 HTTP 缓存机制,但本文不借助这些框架, 而是直接以基本的 Node.js 程序与 Chrome 浏览器来描述 HTTP 中最基本的缓存机制, 涉及到的 HTTP 头字段 包括 Cache-Control, Last-Modified, If-Modified-Since, Etag, If-None-Match 等。

除 HTTP 缓存之外,Web 性能优化还有很多其他途径,比如 预加载和预渲染脚本异步载入 等。

HTTP 缓存简介

谈起 HTTP 缓存你首先想到的一定是磁盘缓存,以及 304 状态码。 这是浏览器处理缓存的两种情况:

  • 浏览器询问服务器缓存是否有效,服务器返回 304 指示浏览器使用缓存。
  • 资源仍然处于有效期时,浏览器会直接使用磁盘缓存(在刷新时稍有不同,见下文)。

[图片上传中...(image-6566b5-1630388747574-3)]

图中 favicon.ico 直接来自磁盘缓存,而 localhost 文档则来自 304 缓存。 上述行为中涉及到 3 个 HTTP 响应头字段:

  • Cache-Control 响应头表示了资源是否可以被缓存,以及缓存的有效期。
  • Etag 响应头标识了资源的版本,此后浏览器可据此进行缓存以及询问服务器。
  • Last-Modified 响应头标识了资源的修改时间,此后浏览器可据此进行缓存以及询问服务器。

Cache-Control

Cache-Control 在 HTTP 响应头中,用于指示代理和 UA 使用何种缓存策略(感谢 Kingsley Chen 指出此前对 no-cache 描述的错误)。比如:

  • no-cache 为本次响应不可直接用于后续请求(在没有向服务器进行校验的情况下)
  • no-store 为禁止缓存(不得存储到非易失性介质,如果有的话尽量移除,用于敏感信息)
  • private为仅 UA 可缓存
  • public为大家都可以缓存。

Cache-Control为可缓存时,同时可指定缓存时间(比如public, max-age:86400)。 这意味着在 1 天(60x60x24=86400)时间内,浏览器都可以直接使用该缓存(此时服务器收不到任何请求)。 当然浏览器也有权随时丢弃任何一项缓存,因此这里可能有一致性问题。 注意下图中状态码附近的 from disk cache 标识。

[图片上传中...(image-38a59a-1630388747573-2)]

其服务器代码如下:

import http from 'http'

let server = http.createServer((req, res) => {
  res.setHeader('Cache-Control', 'public, max-age=86400')
  res.end('harttle.land')
})

server.listen(3333)

除了 Cache-Control 中的 max-age 外,ExpiresVary 等头字段也可用来设置缓存的有效性。

Etag

如果资源本身确实会随时发生改动,还用 Cache-Control 就会使用户看到的页面得不到更新。 但如果还希望利用 HTTP 缓存(万一资源没变呢),这就需要有条件的(conditional)HTTP 请求。

Etag 响应头字段表示资源的版本,浏览器在发送请求时会带 If-None-Match 头字段, 来询问服务器该版本是否仍然可用。如果服务器发现该版本仍然是最新的, 就可以返回 304 状态码指示 UA 继续使用缓存。注意下图中的 If-None-Match 字段。

[图片上传中...(image-8bc5e2-1630388747573-1)]

其服务器端代码如下:

import http from 'http'

let server = http.createServer((req, res) => {
  console.log(req.url, req.headers['if-none-match'])
  if (req.headers['if-none-match']) {
    // 检查文件版本
    res.statusCode = 304
    res.end()
  }
  else {
    res.setHeader('Etag', '00000000')
    res.end('harttle.land')
  }
})

server.listen(3333)

Last-Modified

Etag 类似,Last-Modified HTTP 响应头也用来标识资源的有效性。 不同的是使用修改时间而不是实体标签。对应的请求头字段为If-Modified-Since, 见下图:

[图片上传中...(image-c6c4e8-1630388747573-0)]

其服务器端代码如下:

import http from 'http'

let server = http.createServer((req, res) => {
  console.log(req.url, req.headers['if-modified-since'])
  if (req.headers['if-modified-since']) {
    // 检查时间戳
    res.statusCode = 304
    res.end()
  }
  else {
    res.setHeader('Last-Modified', new Date().toString())
    res.end('harttle.land')
  }
})

server.listen(3333)

浏览器刷新

撰写这篇文章的过程中,Harttle 使用了很多 Chrome 浏览器的截图。 如果你使用浏览器调试,可能也需要了解刷新按钮的行为。

正常重新加载

按下刷新按钮或快捷键(在 MacOS 中是 Cmd+R)会触发浏览器的“正常重新加载”(normal reload), 此时浏览器会执行一次 Conditional GETCache-Control 等缓存头字段会被忽略,并且带If-None-Match, If-Modified-Since等头字段。 此时服务器总会收到一次 HTTP GET 请求。 在 Chrome 中按下刷新,浏览器还会带如下请求头:

Cache-Control:max-age=0

注意:在地址栏重新输入当前页面地址并按下回车也会当做刷新处理, 这意味着只有从新标签页或超链接打开时,才能观察到直接使用硬盘缓存的情况。

强制重新加载

在 Chrome 中按下 Cmd+Shift+R (MacOS)可以触发强制重新加载(Hard Reload), 此时包括页面本身在内的所有资源都不会使用缓存。 浏览器直接发送 HTTP 请求且不带任何条件请求字段。

本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可,转载注明来源即可: https://harttle.land/2017/04/04/using-http-cache.html。学识粗浅写作仓促,如有错误辛苦评论或 邮件 指出。

相关文章

  • [转载] 使用 HTTP 缓存:Etag, Last-Modif

    原文链接:https://harttle.land/2017/04/04/using-http-cache.htm...

  • 初识HTTP缓存-ETag

    最近在学习网站性能优化相关的内容,关于网站优化点特别多而HTTP缓存也是比较重要的一部分,于是今天就着重看下HTT...

  • http缓存 cdn缓存

    一、ETag 初识HTTP缓存-ETag 刷新页面后再次请求在请求头中却有个 If-None-Match: W/"...

  • 前端缓存接口数据的实现

    前端缓存 API 接口数据,前端怎么知道数据是否变了,该不该取缓存的数据呢。可以采用 HTTP 协商缓存 ETag...

  • 移动端性能优化(2)

    缓存类 合理利用浏览器缓存 除了上面说到的使用Cache-Control、Expires、Etag和Last-Mo...

  • 移动端性能优化(2)

    缓存类 合理利用浏览器缓存 除了上面说到的使用Cache-Control、Expires、Etag和Last-Mo...

  • HTTP 缓存相关的响应头信息

    响应头信息有: Cache-Control // 控制缓存 Expire // 控制缓存 ETag // 校验缓存...

  • RXJava中如何使用ETag缓存

    还是启动图的问题,上一个版本使用队列缓存启动图,但是ios端总是出问题,不得已,在这一版中,后台又重现制定了启动图...

  • [转载]HTTP缓存机制

    HTTP 缓存到底怎么实现呢?之前课堂上讲过怎么突然想不起来了... 从头开始捋一捋吧!一、 思路1,无缓存浏览器...

  • iOS 一些缓存使用技巧

    1 :一般缓存用苹果的url 缓存即可。2:缓存的过期处理 对于文件缓存借助ETag 或者Last-Modifie...

网友评论

      本文标题:[转载] 使用 HTTP 缓存:Etag, Last-Modif

      本文链接:https://www.haomeiwen.com/subject/bkdziltx.html