深入理解 HTTP 缓存机制:从原理到实践优化

更新日期: 2025-06-13阅读: 53标签: http

一、HTTP 缓存的核心价值与基本分类

在 Web 性能优化体系中,HTTP 缓存是减少网络请求、提升响应速度的关键手段。通过复用本地已缓存的资源,不仅能降低服务器负载,还能将资源加载时间从网络传输耗时缩短至本地读取耗时。根据缓存策略的不同,HTTP 缓存主要分为强缓存协商缓存两类,两者的核心区别在于:强缓存直接使用本地缓存而无需请求服务器,协商缓存则需要服务器参与验证缓存有效性。


二、强缓存:本地资源的 “免验证通道”

强缓存的本质是通过响应头字段告诉浏览器 “资源在 XX 时间内无需重新请求”,适用于更新频率低的静态资源(如 css、JS、图片等)。
1. 强缓存的两种实现方式

(1)Expires:HTTP/1.0 的时间戳标记

Expires 字段以绝对时间戳形式指定资源过期时间,例如:
Expires: Wed, 21 Oct 2027 07:28:00 GMT 
浏览器通过对比本地时间与 Expires 值判断缓存是否有效。但该方式存在明显缺陷:若用户修改本地系统时间(如调至未来),会导致所有基于 Expires 的缓存失效。

(2)cache-control:HTTP/1.1 的相对时间控制

cache-control 以相对时间(秒)定义缓存有效期,优先级高于 Expires,例如:
cache-control: public, max-age=31536000  // 缓存1年  
  • public表示资源可被客户端和代理服务器共享缓存;
  • max-age定义从首次请求开始计算的缓存时长,避免了 Expires 依赖客户端时间的问题。
2. 在服务端设置 cache-control
以 Express 框架为例,设置强缓存的代码如下:
const express = require('express');  
const app = express();  

app.get('*', (req, res) => {  
  // 设置缓存10分钟(600秒),公共缓存  
  res.setHeader('cache-control', 'public, max-age=600');  
  res.end('资源内容');  
});  

app.listen(3031);  
3. cache-control 的高级指令解析
指令分类常用值作用描述
可缓存性public资源可被任何设备缓存(包括代理服务器)
private资源仅可被用户本地浏览器缓存,代理服务器不可缓存
no-cache强制缓存前需先向服务器验证资源有效性(走协商缓存流程)
no-store禁止任何形式的缓存,每次请求都重新获取资源
到期时间max-age=600资源在 600 秒内有效
s-maxage=3600共享缓存(如代理服务器)的过期时间,优先级高于 max-age
重新验证策略must-revalidate缓存过期后必须向服务器验证,否则不可使用
immutable(实验性)资源内容永久不变,无需验证(仅 HTTPS 场景有效)
4. 内存缓存与磁盘缓存的差异
  • 内存缓存(Memory Cache):读取速度极快,但随浏览器标签页关闭而释放,主要存储当前页面资源(如脚本、样式)。
  • 磁盘缓存(Disk Cache):容量大、持久化存储,适用于大文件或跨站点缓存,浏览器会根据文件大小和内存占用自动选择存储位置(例如大文件优先存入磁盘)。


三、协商缓存:服务器参与的 “智能验证”

当强缓存失效或资源未设置强缓存时,浏览器会发起请求并通过协商缓存机制验证资源是否更新,服务器返回 304 状态码时可直接使用本地缓存。
1. Last-Modified 与 If-Modified-Since:基于时间的验证
  • 响应头 Last-Modified:标识资源最后修改时间,例如:
    Last-Modified: Mon, 10 Jun 2024 12:00:00 GMT  
  • 请求头 If-Modified-Since:浏览器携带上次获取的 Last-Modified 值,服务器对比当前资源修改时间,若未变化则返回 304。
缺陷:时间精度仅到秒级,且文件元数据修改(如重新保存)可能导致时间变化而内容未变。
2. ETag 与 If-None-Match:基于内容的指纹验证
  • 响应头 ETag:通过哈希算法(如 MD5)生成资源内容的唯一标识,例如:
    ETag: "5f3b2a1e1c4b3a2d4c5a"  
  • 请求头 If-None-Match:浏览器携带上次获取的 ETag 值,服务器对比当前资源哈希,一致则返回 304。
优势
  • 精度更高,仅内容变化时 ETag 才会改变;
  • 优先级高于 Last-Modified,两者同时存在时以 ETag 为准。
3. 协商缓存的 Express 实现示例
const express = require('express');  
const fs = require('fs');  
const crypto = require('crypto');  

const app = express();  
const md5 = (data) => crypto.createHash('md5').update(data).digest('hex');  

app.get('/static/:file', (req, res) => {  
  const file = `./static/${req.params.file}`;  
  fs.readFile(file, 'utf8', (err, data) => {  
    if (err) return res.status(500).send('错误');  
    
    // 生成ETag  
    const currentEtag = md5(data);  
    // 获取浏览器携带的ETag  
    const ifNoneMatch = req.headers['if-none-match'];  
    
    if (ifNoneMatch === currentEtag) {  
      res.status(304).end(); // 资源未更新,返回304  
      return;  
    }  
    
    // 资源更新,返回新内容和ETag  
    res.setHeader('ETag', currentEtag);  
    res.send(data);  
  });  
});  

app.listen(3031);  


四、缓存策略的最佳实践

  1. 静态资源缓存策略
    • CSS、JS、图片等长期不变资源:设置cache-control: public, max-age=31536000(1 年),并通过版本号(如app.v1.0.js)控制更新;
    • 频繁更新的资源:设置max-age=3600(1 小时),兼顾性能与更新效率。
  2. 动态资源缓存策略
    • 不常变化的动态数据:使用private, max-age=60(1 分钟),减少重复请求;
    • 实时数据:设置no-cache或no-store,强制每次请求服务器。
  3. 缓存优先级与调试
    • 强缓存 > 协商缓存 > 重新请求;
    • 浏览器调试时按Ctrl+Shift+R(强制刷新)可绕过所有缓存,便于验证更新。


五、总结

HTTP 缓存机制通过强缓存与协商缓存的分层设计,在 “性能优化” 与 “资源更新” 之间找到了平衡。合理设置缓存策略不仅能提升用户体验,还能降低服务器压力。实际应用中,需根据资源特性(更新频率、文件类型)灵活配置响应头,同时结合版本控制、浏览器调试工具持续优化缓存效果。

链接: https://fly63.com/article/detial/12787

HTTPS 常见部署问题及解决方案

到任何有关部署 HTTPS 或 HTTP/2 的问题,都推荐先用 Qualys SSL Labs SSL Server Test 跑个测试,大部分问题都能被诊断出来。

HTTP请求头和响应头部包括的信息有哪些【HTTP请求头各字段解释】

每个HTTP请求和响应都会带有相应的头部信息。默认情况下,在发送XHR请求的同时,还会发送下列头部信息: Accept、Accept-Charset、Accept-Encoding、Connection、Host

服务器响应常用状态码及含义_ajax请求中http返回的状态码大全

HTTP状态码是用以表示网页服务器HTTP响应状态的3位数字代码,其中第一位数字表示响应类别,响应类别从1到5分为五种,分别代表:临时响应、成功、重定向、请求错误、服务器错误。

HTTPS 如何保证数据传输的安全性

在客户端与服务器数据传输的过程中,HTTP协议的传输是不安全的,也就是一般情况下HTTP是明文传输的。但HTTPS协议的数据传输是安全的,也就是说HTTPS数据的传输是经过加密的

http协议的发展历史

在最早的时候,第一个定稿的http协议是http/0.9版本,在这个版本里面,http协议,它的内容,非常非常的简单 只有一个命令。http协议的历史,其中当然还有https,https是http的安全版本,它实际使用的内容跟http/1.1没有很大的区别

axios 模块化封装_对axios的二次封装的实现

Axios 是一个基于 promise 的 HTTP 库 ,使用了axios来进行数据的请求,一般都需要我们对它进行封装处理。下面简单介绍下如何对axios的二次封装的实现,以及在vue中的使用。

HttpClient的3种超时

设置ConnectionPoolTimeout:这定义了从ConnectionManager管理的连接池中取出连接的超时时间,此处设置为1秒。设置ConnectionTimeout:这定义了通过网络与服务器建立连接的超时时间。Httpclient包中通过一个异步线程去创建与服务器的socket连接

HTTP 请求头中的 Remote_Addr,X-Forwarded-For,X-Real-IP

X-Forwarded-For一般是每一个非透明代理转发请求时会将上游服务器的IP地址追加到X-Forwarded-For的后面,使用英文逗号分割;X-Real-IP一般是最后一级代理将上游IP地址添加到该头中;X-Forwarded-For是多个IP地址,而X-Real-IP是一个

HTTP协议中的短轮询、长轮询、长连接和短连接

HTTP协议是基于请求/响应模式的,因此只要服务端给了响应,本次HTTP连接就结束了,根本没有长连接这一说。网络上说HTTP分为长连接和短连接,其实本质上是说的TCP连接。TCP连接是一个双向的通道,它是可以保持一段时间不关闭的,因此TCP连接才有真正的长连接和短连接这一说。

常见HTTP请求错误码

一些常见的状态码为:200 - 服务器成功返回网页;404 - 请求的网页不存在;503 - 服务不可用。1xx(临时响应):表示临时响应并需要请求者继续执行操作的状态代码。2xx (成功):表示成功处理了请求的状态代码。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!