Egg.js 服务端 HTML 强缓存问题排查与解决

问题现象与影响

某次线上更新后发现:HTML 页面内容未更新,用户浏览器反复刷新仍显示旧版本。经排查发现服务端对 HTML 文件设置了强缓存,导致浏览器直接从本地缓存加载 HTML,而未向服务器请求最新内容。

2.排查路径

基于请求链路,从浏览器缓存、CDN缓存、nginx 缓存、服务端缓存等多个维度进行排查。

2.1 客户端(浏览器)层面

例如通过 Service Worker 控制缓存策略

js 复制代码
// sw.js
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(res => {
      return res || fetch(event.request);
    })
  );
});

基于此,可以通过 curl 请求页面,发现请求头仍然存在强缓存,说明浏览器未对 HTML 设置缓存

2.2 CDN 层面

因请求 HTML 的域名并非 CDN 的域名,因此 CDN 不会对该 HTML 文件进行缓存。

2.3 NGINX 层面

检查了 NGINX 配置,并确认了 NGINX 配置没有对 HTML 文件进行缓存。

2.4 服务端层面

在服务端中,可能在业务代码的中间件、响应头以及第三方代码模块中设置了强缓存。

最终根据响应头的标识,全局搜索,最终定位到是服务器 egg-static 插件配置问题,通过 egg-static 的源码我们发现,在返回数据时,会对 HTML 文件设置强缓存的请求头。

顺便一提: 在 Node 服务中,HTML 模版不应该转变成静态资源,而是应该使用 render 方法进行模版渲染。

3.解决方案

回归业务场景,egg-static 基于 koa-static-cache 实现,默认配置为:

js 复制代码
{
  maxAge: 31536000, // 1年缓存
  buffer: true,
  dynamic: true,
  preload: false
}

在 koa-static-cache 中,存在 files 配置,它是一个文件管理器对象,key 为文件名称,value 是文件制定配置 FileMeta,用于管理文件返回值的相关配置,其中 maxAge 配置用于指定缓存时间,当 maxAge 为 0 时,表示不缓存。

源码连接: github.com/eggjs/koa-s...

ts 复制代码
export interface FileMeta {
  maxAge?: number;
  cacheControl?: string;
  buffer?: Buffer;
  zipBuffer?: Buffer;
  type?: string;
  mime?: string;
  mtime?: Date;
  path?: string;
  md5?: string;
  length?: number;
}

在源码中,会先执行 loadFile 方法,根据文件名称从 files 中获取文件的配置,然后返回文件配置内容。(LoadFile --> 获取文件配置项 --> 根据配置返回文件内容)

基于此,恰好 koa-static-cache 暴露了 可以配置 files 对象的参数,当配置 HTML 文件的 maxAge 设置为 0 时,可去除强缓存。

最终修改后,我们通过 curl 请求页面,发现请求头已经没有强缓存了。

PS: 其实还有一个最简单的解决方案,即 egg/koa-static-cache (github.com/eggjs/koa-s...) 支持cache-control字段传递函数,这样可以根据文件名称自定义请求头参数,目前已提 PR (github.com/eggjs/koa-s...)

4.总结

通过以上排查,最终定位到是服务器 egg-static 插件配置问题,导致 HTML 文件被缓存。

基于此,可以通过 egg-static 中的 files 配置,对 HTML 文件进行缓存控制。

相关推荐
寅时码1 小时前
React 之死·终章:一个 useRef,把闭包陷阱、依赖数组、漫天 rerender 全送走
前端·react.js·ai编程
不好听6131 小时前
HTML 事件监听机制:从 DOM Level 0 到 React 合成事件
前端·react.js·html
wordbaby1 小时前
为什么刷新页面就 404?聊聊 SPA 路由与 Nginx 的那点事
前端
不好听6132 小时前
React 核心概念:JSX、组件与数据驱动
前端·react.js
触底反弹2 小时前
🔥 React 零基础入门(中):500 行屎山代码到组件化的蜕变
前端·javascript·react.js
不好听6132 小时前
React vs Vue:两大前端框架技术选型深度对比
前端·vue.js·react.js
GuWenyue2 小时前
Cursor黑盒拆解!1套LangChain.js手写Mini编程Agent,自动生成React项目,效率提升60%
前端·数据库·人工智能
GuWenyue2 小时前
传统Agent工具两大痛点!300行代码落地MCP跨语言工具,彻底解耦LLM与工具
前端·人工智能·算法
小林ixn3 小时前
从 onclick 到 React 合成事件,再到完整应用逻辑:一次前端架构的深度剖析
前端·react.js·前端框架
Csvn3 小时前
🧩「找不到模块」排查全记录——Monorepo 下 TypeScript 路径别名的 5 种「不通」与根治方案
前端