WHAT - 静态资源缓存穿透

文章目录

  • [1. 动态哈希命名的基本思路](#1. 动态哈希命名的基本思路)
  • [2. 具体实现](#2. 具体实现)
    • [2.1 Vite/Webpack 配置动态哈希](#2.1 Vite/Webpack 配置动态哈希)
    • [2.2 HTML 文件中动态引用](#2.2 HTML 文件中动态引用)
      • 手动引用
      • [使用 index.html 模板动态插入](#使用 index.html 模板动态插入)
    • [2.3 结合 `Cache-Control` 避免缓存穿透](#2.3 结合 Cache-Control 避免缓存穿透)
    • [2.4 适用于多环境的动态策略](#2.4 适用于多环境的动态策略)
  • 总结

在多环境部署中,静态资源缓存穿透是一个常见问题,尤其是当前端或后端的静态资源未正确更新,导致旧版本被意外加载。

对于这种问题,动态哈希命名策略是一种有效的解决方案,通过给资源文件添加哈希值来确保浏览器获取最新版本。注意,一般在打包工具的 production 生产模式下 build 后的产物都会自动使用哈希命名配置,无需手动配置。今天主要是介绍背后的实现原理,以下是具体的实现方式:

1. 动态哈希命名的基本思路

  • 在构建时,为静态资源(JS、CSS、图片等)文件名添加基于内容的哈希值(如 MD5、SHA-256)。
  • 在 HTML 或配置文件中,引用时使用带有哈希值的文件名,确保每次构建后的新文件名唯一,避免缓存问题。
  • 结合 Cache-Control 策略,让浏览器长时间缓存文件,只有当文件内容变更时才会重新下载。

2. 具体实现

2.1 Vite/Webpack 配置动态哈希

在 Vite(或 Webpack)中,可以通过 build.rollupOptions.outputoutput.filename 进行哈希处理:

Vite (vite.config.ts)

ts 复制代码
import { defineConfig } from 'vite';

export default defineConfig({
  build: {
    assetsDir: 'assets',
    rollupOptions: {
      output: {
        entryFileNames: 'assets/[name].[hash].js',
        chunkFileNames: 'assets/[name].[hash].js',
        assetFileNames: 'assets/[name].[hash].[ext]',
      }
    }
  }
});

Webpack (webpack.config.js)

js 复制代码
module.exports = {
  output: {
    filename: 'js/[name].[contenthash].js',
    chunkFilename: 'js/[name].[contenthash].js',
  },
};

这样,每次构建时,生成的 JS/CSS 文件都会带上基于内容的 hash,确保不同版本的文件不会相互覆盖。

2.2 HTML 文件中动态引用

手动引用

在 HTML 中,可以通过 <script><link> 直接引入带哈希的文件:

html 复制代码
<script src="/assets/app.abc123.js"></script>

使用 index.html 模板动态插入

如果是 Vite,可以使用 vite-plugin-html 插件:

ts 复制代码
import { createHtmlPlugin } from 'vite-plugin-html';

export default defineConfig({
  plugins: [
    createHtmlPlugin({
      inject: {
        data: {
          title: 'My App',
        },
      },
    }),
  ],
});

index.html 中:

html 复制代码
<script type="module" src="<%= htmlWebpackPlugin.files.js %>"></script>

2.3 结合 Cache-Control 避免缓存穿透

nginxCDN 服务器配置 Cache-Control,让静态资源长期缓存:

nginx 复制代码
location /assets/ {
  expires max;
  add_header Cache-Control "public, immutable";
}

immutable 表示文件不会更改,即使 304 Not Modified 也不需要重新验证。

同时,确保 index.html 不被缓存,以便引用最新的哈希文件:

nginx 复制代码
location / {
  expires -1;
  add_header Cache-Control "no-cache, must-revalidate";
}

2.4 适用于多环境的动态策略

vite.config.tswebpack.config.js 中,可以根据环境变量来控制 hash 策略:

ts 复制代码
const isProduction = process.env.NODE_ENV === 'production';

export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        entryFileNames: isProduction ? 'assets/[name].[hash].js' : 'assets/[name].js',
      },
    },
  },
});

这样,在 开发环境 中不会生成哈希,方便调试,而 生产环境 则启用哈希。

总结

  • 通过 文件名+哈希 方式,确保静态资源变更时不会被缓存拦截。
  • 配置 Nginx/CDNindex.html 不缓存,而 JS/CSS 采用长时间缓存。
  • Vite/Webpack 结合 环境变量 实现多环境适配。

这样就能有效解决缓存穿透问题,让前端资源在多环境部署时始终保持最新!

相关推荐
知识即是力量ol5 小时前
基于 Redis 实现白名单,黑名单机制详解及应用场景
数据库·redis·缓存
fengxin_rou7 小时前
Redis 从零到精通:第一篇 初识redis
数据库·redis·缓存
陌上丨10 小时前
Redis内存使用率在95%以上,请问是什么原因?如何解决?
数据库·redis·缓存
dawdo22211 小时前
自己动手从头开始编写LLM推理引擎(9)-KV缓存实现和优化
缓存·llm·transformer·qwen·kv cache
小北方城市网12 小时前
RabbitMQ 生产级实战:可靠性投递、高并发优化与问题排查
开发语言·分布式·python·缓存·性能优化·rabbitmq·ruby
陌上丨12 小时前
什么是Redis的大Key和热Key?项目中一般是怎么解决的?
数据库·redis·缓存
小园子的小菜12 小时前
深入剖析HBase HFile原理:文件结构、Block协作与缓存机制
数据库·缓存·hbase
廋到被风吹走13 小时前
【缓存优化】缓存穿透:布隆过滤器(Guava/RedisBloom)
缓存·guava
Moshow郑锴13 小时前
Spring Boot Data API 与 Redis 集成:KPI/图表/表格查询的缓存优化方案
spring boot·redis·缓存
小马爱打代码13 小时前
MyBatis:缓存体系设计与避坑大全
java·缓存·mybatis