首页/文章/八股文

前端项目中,强缓存和协商缓存的配置

2025-03-24
18027 分钟
...

前端缓存分为HTTP缓存和浏览器缓存

  1. HTTP缓存(本文重点)
    • 强缓存
    • 协商缓存
  2. 浏览器缓存
    • 比较熟悉的 cookie,localstorage sessionstorage indexDB…
    • 或者cacheStorage 请求的缓存,如果本地有取本地的

先说总结的内容
webpack配置(主要是文件名上有个hash值,便于服务器校验文件有没有修改)
使用hash的好处就是,使版本发布之后,使之前文件的强缓存失效

module.exports = {
  output: {
    filename: 'bundle.[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
  },
};

nginx配置 (主要是配置html文件不强缓存,别的文件使用强缓存+协商缓存)

location / {
    root   www; # 访问根目录
    index  index.html index.htm; # 入口文件
}

location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
    # 启用强缓存的静态资源强缓存过期之后使用协商缓存
    expires 7d; # 设置缓存时间为7天
     if_modified_since before;
    add_header Cache-Control "max-age=604800, public"; # 设置强缓存
}

location ~* \.html$ {
    # 不启用强缓存的 HTML 文件
    expires off;
}
  • if_modified_since before 启用了 If-Modified-Since 验证,允许浏览器发送 If-Modified-Since 头部来验证资源是否已更改。
  • add_header Cache-Control 用于设置强缓存的 Cache-Control 头部,以便在资源的强缓存过期后,浏览器可以使用 If-Modified-Since 验证。
    这样配置允许浏览器在资源的强缓存过期后,发送 If-Modified-Since 头部的请求来验证资源是否需要更新。如果资源未更改,Nginx将返回状态码 304 (Not Modified),并且浏览器将使用本地缓存的资源。

总之,虽然强缓存是首选的缓存策略,但协商缓存仍然可以提供额外的性能优势,并减少不必要的网络请求,对于代理前端静态资源的Nginx配置仍然有用。

强缓存 (Cache-Control 和 Expires)

就是设置时间,时间不到就强制一直取本地的,设置了之后就不用跟服务器协商了

Expires 和 Chache-control 都是标识时间的字段,需要注意的是如果二者同时出现,Chache-control 的优先级是高于 Expires 。

但 Expires 是 HTTP1.0 的规范,时间格式是 GTM 字符串,如如果服务器时间和客户端时间差别较大时,会导致内存混乱。而服务器的时间和用户实际时间不正常是很正常的现象,所以在使用 Expires 的时候会出现一些问题,建议还是使用 Chache-control 来标识时间

Cache-Control 这个字段是 http 1.1 的规范,一般常用该字段的 max-age 值来进行判断,它是一个相对时间所以比较准确

配置方法
  • webpack 使用 asset-modules 的 output 配置中的 cache 字段来控制生成文件的缓存策略
module.exports = {
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',
    assetModuleFilename: '[name][contenthash][ext]',
  },
};

这个配置使用了 [contenthash] 来生成文件名,这意味着如果文件内容没有改变,contenthash 也不会改变,从而利用浏览器的强缓存

  • Nginx 中设置强缓存
location /static/ {
    alias /path/to/static/files;
    expires 30d;  # 设置缓存时间为30天
}
  • NodeJs
const express = require('express');
const app = express();

app.use('/static', express.static('public', {
  maxAge: '30d',  // 设置缓存时间为30天
}));
协商缓存 (Last-Modified 和 ETag)

发请求到服务器,由服务器判断标签的值是不是最新的,是最新的就不返回内容,否则就返回内容
协商缓存是由服务器来决定,这个资源到底是否更新。整个过程也是涉及到两个字段。在第一次请求的 header 中会出现 Last-Modified 或是 Etag,注意是第一次请求的时候就会有,因为要通过这个字段来判断资源是否可用。

如果是 Etag 对应的是 if-None-Match 字段,是一段唯一标识符,告诉服务器本地缓存文件的最后修改时间。

如果是 Last-Modified 对应的是 if-Modified-Since 字段,是一段时间格式的字符串,比如是哈希值,服务端判断哈希是否一致。HTTP中并没有指定如何生成 ETag,这个由开发者自行决定。

以上两种,如果服务端判断一样,则返回 304 Not Modified,如果不一致则返回新的资源,并且更新本地缓存

配置方法
  • webpack 使用 output 配置的 filename 中添加 [contenthash] 来生成资源文件名,并生成 ETag 头部,从而启用协商缓存。
module.exports = {
  output: {
    filename: 'bundle.[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
  },
};
  • Nginx 中设置强缓存
location /static/ {
    alias /path/to/static/files;
    if_modified_since exact;
    add_header ETag "your_etag_value";
}
  1. if_modified_since exact; 指示 Nginx 使用精确的 If-Modified-Since 验证,这意味着如果 Last-Modified 与请求头中的 If-Modified-Since 匹配,Nginx将返回状态码304。
  2. add_header ETag “your_etag_value”; 添加 ETag 头部到响应中,浏览器将与请求头中的 If-None-Match 进行比较。
  • NodeJs
const express = require('express');
const app = express();

app.use('/static', express.static('public', {
  etag: 'your_etag_value',
  lastModified: true,
}));

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
八股文2025-03-24
OPTIONS请求条件与浏览器安全策略CORS
1\. 什么时候会发送OPTIONS请求 在 Web 开发中, 请求是一种 HTTP 请求方法,通常与 CORS(跨源资源共享,Cross Origin Resource Sharing) 机制相关。它主要用于预检(preflight)请求,以检查服务器是否允许特定的跨域请求。以下是详细说明: 1.1. 发送OPTIONS请求条件 1.1.1. 跨域请求且不是简单请求 当发起的请求是跨域的(即请求的目标域名与当前页面域名不同),并且不满...
面试面试官
八股文2025-03-24
搞定前端性能优化问题
一、首屏加载优化 首屏加载是指 用户打开页面到第一个可视内容呈现出来之间的时间 。它直接影响用户对网站的第一印象,因此在前端性能优化中具有最高的优先级。 优化首屏加载的目标是 尽可能快地把关键内容展示给用户,减少白屏时间,提升首屏体验。 常见的优化方式包括资源按需加载、预加载关键资源、使用服务端渲染或静态生成等。 1\. 资源按需加载(Lazy Load) 在前端应用中,JS、CSS、图片等资源如果全部打包在一起加载,会极大拖慢页面的加...
面试面试官
八股文2025-03-19
JS宏任务,微任务,DOM渲染,requestAnimationFrame执行顺序比较
本文小结 1. 宏任务和微任务都是异步任务。 2. 优先级: 3. 慢于同步任务。本次实践中,第一次执行的时间比微任务慢,比宏任务和DOM渲染快。 来自MDN的理论部分 每个代理都是由 事件循环 驱动的,事件循环负责收集用事件(包括用户事件以及其他非用户事件等)、对任务进行排队以便在合适的时候执行回调。然后它执行所有处于等待中的 JavaScript 任务(宏任务),然后是微任务,然后在开始下一次循环之前执行一些必要的渲染和绘制操作。...
面试面试官
八股文2025-03-18
一文总结vue和react的区别
Vue.js 和 React.js 都是流行的 JavaScript 前端框架,用于构建用户界面。它们在设计理念、语法和使用方式等方面有一些区别,以下是一些比较详细的对比: 设计理念: Vue.js :Vue.js 是一款轻量级、渐进式的框架,它专注于视图层的渲染和状态管理。Vue 的核心思想是通过数据驱动视图的变化,提供了一套简洁的模板语法和响应式数据绑定机制,使得开发者可以更便捷地构建交互式的用户界面。 React.js :Reac...
面试面试官
八股文2025-03-10
最全的Map 和 WeakMap的区别
和 的区别及面试追问知识点 一、两者区别总结 (一)基本概念 和 均为 JavaScript 中用于存储键值对的数据结构,但在多个关键特性上有显著差异。 (二)键的类型限制 1. 键类型无严格限制,可接受基本数据类型(如字符串、数字、布尔值)以及引用数据类型(如对象、数组、函数)。 示例代码: 2. 键必须为对象,使用基本数据类型作为键会抛出错误。 示例代码: (三)垃圾回收机制 1. 对键和值采用强引用,只要 对象存在,其引用的键值对...
面试面试官
八股文2025-03-07
hash与history路由模式区别hash与history的区别
hash与history的区别 两种路由模式原因原因 对于 这类渐进式前端开发框架, 为了构建 SPA(单页面应用), 需要引入前端路由系统, 这也就是 存在的意义。 前端路由的核心,就在于 —— 改变视图的同时不会向后端发出请求。 因此有两种路由 1. : 即地址栏 URL 中的 符号(此 不是密码学里的散列运算)。 比如这个 URL: , 的值为 。它的特点在于:hash 虽然出现在 URL 中, 但不会被包括在 HTTP 请求中,...
面试面试官

评论

请登录后发表评论

去登录
加载评论中...

目录