还搞不明白浏览器缓存?

一:前言

浏览器缓存浏览器储存 是不一样的,友友们不要混淆,关于浏览器储存,具体可以看这篇文章 : 一篇打通浏览器储存

这里大概介绍一下:

cookies localStorage sessionStorage IndexedDB
服务端设置 一直存在 页面关闭就消失 一直存在
4K 5M 5M 无限大
自动携带在http请求头中 不参与后端 不参与后端 不参与后端
默认不允许跨域,但可以设置 可跨域 可跨域 可跨域

二:强缓存

强缓存是指浏览器在请求资源时,如果本地有符合条件的缓存,那么浏览器会直接使用缓存而不会向服务器发送新的请求。这可以通过设置 Cache-ControlExpires 响应头来实现。

2.1:Cache-Control 头详解

Cache-Control 是一个非常强大的HTTP头部字段,它包含多个指令,用以控制缓存的行为:

  • max-age:指定从响应生成时间开始,该资源可被缓存的最大时间(秒数)。
  • s-maxage :类似于 max-age,但仅对共享缓存(如代理服务器)有效。
  • public:表明响应可以被任何缓存存储,即使响应通常是私有的。
  • private:表明响应只能被单个用户缓存,不能被共享缓存存储。
  • no-cache:强制缓存在使用前必须先验证资源是否仍然新鲜。
  • no-store:禁止缓存该响应,每次请求都必须获取最新数据。
  • must-revalidate:一旦资源过期,必须重新验证其有效性。

例如,通过设置 Cache-Control: max-age=86400,可以告诉浏览器这个资源可以在本地缓存24小时。在这段时间内,如果再次访问相同URL,浏览器将直接使用缓存中的副本,而不与服务器通信。

2.2:Expires 头

Expires 是一个较旧的头部字段,用于设定资源过期的具体日期和时间。尽管现在推荐使用 Cache-Control,但在某些情况下,Expires 仍然是有效的。Expires 的值是一个绝对的时间点,而不是相对时间。例如:

js 复制代码
Expires: Wed, 09 Oct 2024 18:29:00 GMT

2.3:浏览器默认行为

当用户通过地址栏直接请求资源时,浏览器通常会自动添加 Cache-Control: no-cache 到请求头中。这意味着即使资源已经存在于缓存中,浏览器也会尝试重新验证资源新鲜度,以确保用户看到的是最新的内容。

三:协商缓存

协商缓存发生在资源的缓存条目已过期设置了 no-cache 指令的情况下。这时,浏览器会向服务器发送请求,并携带上次请求时收到的一些信息,以便服务器决定是否返回完整响应或只是确认没有更新。

3.1:Last-Modified/If-Modified-Since

后端服务器可以为每个资源设置 Last-Modified 头部,表示资源最后修改的时间。当下一次请求同一资源时,浏览器会在请求头中加入 If-Modified-Since 字段,其值为上次接收到的 Last-Modified 值。服务器检查这个时间戳,如果资源自那以后没有改变,则返回304 Not Modified状态码,指示浏览器使用缓存中的版本。

3.2:ETag/If-None-Match

ETag 提供了一种更精确的方法来检测资源是否发生变化。它是基于文件内容计算出的一个唯一标识符。当客户端请求资源时,服务器会在响应头中提供一个 ETag 值。下次请求时,浏览器会发送 If-None-Match 头部,包含之前接收到的 ETag。如果资源未改变,服务器同样返回304状态码;如果有变化,则返回完整的资源及新的 ETag 值。

3.3:比较 Last-Modified 和 ETag

虽然 Last-Modified 简单易用,但它基于时间戳,可能会受到时钟同步问题的影响。相比之下,ETag 更加准确,因为它依赖于资源的实际内容。然而,ETag 计算可能需要更多的服务器处理能力。

四:缓存选择

合理的缓存策略能够显著提升网站性能和用户体验。例如,静态资源(如图片、CSS、JavaScript文件)适合设置较长的缓存时间,而动态内容则需谨慎对待,避免缓存不适当的信息。

  • 使用工具如 Chrome DevTools 来分析页面加载时间和缓存效果。
  • 对不同类型的资源设置合适的 Cache-Control 参数。
  • 注意安全性和隐私保护,确保敏感数据不会被错误地缓存。

五:使用示例

  1. 引入必要的模块 :导入 http, path, fsmime 模块。
  2. 创建HTTP服务器 :使用 http.createServer 创建一个HTTP服务器。
  3. 处理请求
    • 根据请求的URL生成文件路径。
    • 检查文件是否存在。
    • 如果是目录,指向该目录下的 index.html 文件。
  4. 处理协商缓存
    • 获取请求头中的 If-Modified-Since 字段。
    • 比较 If-Modified-Since 与文件的最后修改时间。
  5. 读取文件并发送响应
    • 读取文件内容。
    • 设置响应头(包括 Content-Type, Cache-Control, Last-Modified, ETag)。
    • 发送响应体。
  6. 启动服务器:监听3000端口并启动服务器。

server.js:

js 复制代码
const http = require('http'); // 引入HTTP模块
const path = require('path'); // 引入路径处理模块
const fs = require('fs'); // 引入文件系统模块
const mime = require('mime'); // 引入MIME类型模块

// 创建一个HTTP服务器
const server = http.createServer((req, res) => {
  // console.log(req.url); // /index.html    //   /assets/image/logo.png
  
  // 根据请求的URL生成文件路径
  let filePath = path.resolve(__dirname, path.join('www', req.url));

  // 检查文件或目录是否存在
  if (fs.existsSync(filePath)) {
    const stats = fs.statSync(filePath); // 获取该路径对应的资源状态信息
    // console.log(stats);
    
    const isDir = stats.isDirectory(); // 判断是否是文件夹
    const { ext } = path.parse(filePath); // 获取文件扩展名
    if (isDir) {
      // 如果是目录,则指向该目录下的 index.html 文件
      filePath = path.join(filePath, 'index.html');
    }

    // +++++ 获取前端请求头中的if-modified-since
    const timeStamp = req.headers['if-modified-since']; // 获取请求头中的 If-Modified-Since 字段
    let status = 200; // 默认响应状态码为200
    if (timeStamp && Number(timeStamp) === stats.mtimeMs) { // 如果 If-Modified-Since 存在且与文件最后修改时间相同
      status = 304; // 设置响应状态码为304,表示资源未变更
    }

    // 如果不是目录且文件存在
    if (!isDir && fs.existsSync(filePath)) {
      const content = fs.readFileSync(filePath); // 读取文件内容
      res.writeHead(status, {
        'Content-type': mime.getType(ext), // 设置 Content-Type 头
        'cache-control': 'max-age=86400',  // 设置缓存控制为一天
        // 'last-modified': stats.mtimeMs,  // 资源最新修改时间(可选)
        // 'etag': '由文件内容生成的hash'  // 文件指纹(可选)
      });
      res.end(content); // 发送文件内容作为响应体
    } 
  }
  
});

// 启动服务器,监听3000端口
server.listen(3000, () => {
  console.log('listening on port 3000');
});r.listen(3000, () => {
  console.log('listening on port 3000');
});

index.html:

js 复制代码
<body>
  <h1>midsummer</h1>
  <img src="assets/image/1.png" alt="">
</body>

项目结构如下图,友友们自行准备一张图片,将项目npm init -y 初始化为后端项目,之后下载mime@3 包,在终端输入npx nodemon server.js运行起来,在浏览器中查看http://localhost:3000/index.html ,观察效果。在检查中的网络里看缓存效果,同时友友们可以更改图片或者缓存方式,体验下不同的浏览器缓存方式

相关推荐
饮长安千年月8 分钟前
JavaSec-SpringBoot框架
java·spring boot·后端·计算机网络·安全·web安全·网络安全
代码匠心9 分钟前
从零开始学Flink:揭开实时计算的神秘面纱
java·大数据·后端·flink
Livingbody28 分钟前
Transformers Pipeline 加载whisper模型实现语音识别ASR
后端
WindSearcher1 小时前
大模型微调相关知识
后端·算法
考虑考虑1 小时前
Jpa中的@ManyToMany实现增删
spring boot·后端·spring
笑醉踏歌行1 小时前
NVM,Node.Js 管理工具
运维·ubuntu·node.js
yuan199972 小时前
Spring Boot 启动流程及配置类解析原理
java·spring boot·后端
洗澡水加冰3 小时前
n8n搭建多阶段交互式工作流
后端·llm
陈随易3 小时前
Univer v0.8.0 发布,开源免费版 Google Sheets
前端·后端·程序员
六月的雨在掘金3 小时前
通义灵码 2.5 | 一个更懂开发者的 AI 编程助手
后端