前端多版本零404部署实践:为什么会404,以及怎么彻底解决

这是一篇给“小白也能看懂”的实践文:讲清现象、根因、方案选择与我们的落地实现。

1. 现象:为什么发布新版本后会出现 404?

一个真实场景:

  • 10:00 用户打开了你的网页(加载的是 v1.0.4 的 HTML)
  • 10:10 你发布了 v1.0.5
  • 用户没有刷新页面,继续点击某个功能
  • 页面尝试按旧 HTML 里的地址加载某个 chunk:/assets/pages-about-about.DK5VADjQ.js
  • 服务器上只剩 v1.0.5 的文件,旧的被删了 → 直接 404

关键点:

  • HTML 决定了要加载哪些 JS/CSS(包含具体 hash 文件名)
  • 只要用户手上是旧 HTML,就会请求旧版 hash 的文件
  • 如果服务器把旧文件删了,用户就会 404

2. 根因:不是缓存,而是“源站有没有旧文件”

很多文章只讲“内容哈希 + immutable 缓存”,默认隐含“旧文件在源站/存储里还存在”。

  • 有缓存:命中本地/中间缓存,自然不 404
  • 没缓存:会去源站拉,如果源站还保留旧文件,也不会 404
  • 真正的 404 出在“把旧资源从源站删了”,而不是“浏览器没缓存”

结论:避免 404 的关键不是浏览器缓存,而是“源站/存储上保留旧文件一段时间”。


3. 方案总览(从易到难)

  • A. 接受小概率 404 → 弹窗提示“有新版本,请刷新”
    • 简单,易落地;体验打断、不优雅
  • B. Service Worker 强制刷新
    • 简化实现;用户会被强制 reload,可能丢失上下文
  • C. 不删旧资源(推荐)
    • 源站/存储保留最近 N 个版本的资源;HTML 短缓存
    • 旧 HTML 始终能拿到对应 js/css,零 404,体验最佳
  • D. 网关/Node 层按 manifest 做 chunk 兜底
    • 复杂度高;适合更重的后端网关治理

本文主讲 C 方案。


4. 我们的落地:/assets 聚合 + /versions 备份 + HTML 短缓存

目标:

  • 页面永远从 /assets 加载资源(统一入口,不改路径)
  • 保留最近 3~5 个版本的所有资源在 /assets,旧 HTML 永远能命中
  • 每次发布只切换入口 HTML(dist/current),不动 /assets

目录结构:

dist/ ├─ current/ # 当前入口(index.html、manifest.json 等) ├─ assets/ # 资源聚合池(最近N个版本的 js/css/png/…) └─ versions/ # 版本档案(每次发布的完整备份) ├─ v1.0.5/ │ ├─ index.html │ └─ assets/* ├─ v1.0.4/ └─ ... 

发布流程(关键规则):

  1. 先 build(产物在 dist/build/h5
  2. deploy: 将 dist/build/h5 复制到 dist/current(并写入 manifest.json
  3. 同步最近 N 个版本的 assets/*dist/assets(追加,不覆盖已存在同名 hash 文件)
  4. 清理 dist/assets 中“超出 N 版本范围”的多余文件(可控)

为什么这样零 404:

  • 旧 HTML 会请求旧 hash 文件 → dist/assets 中还在 → 命中成功
  • 新 HTML 请求新 hash → 也在 → 命中成功
  • 版本过渡期内(N版本窗口)不再出现 404

5. 关键实现点(我们做了什么)

  • Vite 输出使用内容哈希:
    • entry/chunk/asset 文件名:assets/[name]-[hash].js|css|…
    • 不再在文件名中带版本号目录(避免同内容不同路径导致缓存失效)
  • 资源聚合器(脚本):
    • 扫描 dist/versions/ 最近 N 个版本的 assets
    • 统一拷贝(或硬链接/软链接)到 dist/assets
    • 清理 dist/assets 中超出窗口的旧文件
  • 入口与资源分离:
    • dist/current 只放 HTML 与轻量入口文件,允许替换
    • dist/assets 仅追加,不随发布清空
  • 预览/线上服务:
    • /dist/current(HTML 短缓存)
    • /assets/*dist/assets(long cache + immutable)
    • 可选兜底:未命中再从 dist/build/h5/assets 查找(用于本地预览与排查)

6. Service Worker 要点(有用但非必须)

  • SW 对 /assets/* 使用“缓存优先 + 网络兜底”或“网络优先 + 缓存兜底”,保证 miss 时回源
  • sw.js、index.html 设短缓存(或 no-cache),SW 能及时更新
  • 若暂不使用 SW,本方案也能零 404;SW 仅作为进一步优化

7. 为什么很多文章不强调“多版本零404”?

  • 默认“旧文件不删”:使用 OSS/CDN/对象存储,资源是追加上传,旧对象长期存在
  • 痛点阈值:发版不频繁、用户会刷新、会话短;小概率 404 用“刷新提示”即可
  • 文档聚焦“原则”:内容哈希 + immutable + HTML 短缓存,被当作默认前置

当你遇到高频发版、长会话、动态导入较多、不能打断用户的场景时,就必须系统性解决“过渡期 404”。


8. 其他常见做法(简短说法,便于对比)

  • 对象存储/CDN是追加写:
    • 带 hash 的静态资源上传到固定前缀,永不覆盖、不清理
    • 每次发版只上传新增;HTML 短缓存可覆盖
  • 原子部署但“只切入口,不清资源”:
    • /releases/<time_hash>/current 指向最新 release;assets 不删
    • 回滚只切回旧 /current
  • Web 服务器层“只换指针,不清资产”:
    • Nginx/OpenResty:/ alias 到当前 HTML 目录;/assets alias 到公共资产池
  • 构建/同步策略“追加而非覆盖”:
    • rsync/脚本:跳过已存在同名文件,只追加;不执行 rm -rf assets
  • CDN 层“天然长留”:
    • 源站是 OSS,CDN 默认不删历史对象;只刷新 HTML

一句话:避免 404 依赖“源站/存储保留旧文件”,不是依赖“浏览器缓存”。


9. 我们的流程清单

  • 统一路径:页面永远从 /assets 加载资源
  • 发布顺序:builddeploy:sync(聚合) → 切换 current
  • 保留策略:versions 保留 10 个档案;assets 保留最近 3~5 个版本资源
  • 清理策略:仅清理超出窗口的文件;不清空 assets 目录
  • 观察/回滚:问题时只切换 HTML(current),资源无需变动
    -(可选)SW:/assets 有兜底;HTML/ sw.js 短缓存

10. FAQ(你可能会问)

  • Q:为什么不用把版本号加进路径(如 /v1.0.5/assets/…)?
    • A:这样会让相同内容的 URL 不同,缓存无法复用。内容哈希已能区分新旧;版本应体现在“保留与聚合”的策略,不应体现在资源 URL。
  • Q:把聚合池直接放到 dist/build/h5/assets 可以吗?
    • A:可以,但构建时常会清空该目录,易被覆盖。更稳妥是用 dist/assets 做聚合池;若坚持放 build 目录,务必在 build 之后再做聚合,并避免之后再执行 build。
  • Q:磁盘会不会涨?
    • A:带 hash 的资源相同内容只存一份;保留 3~5 个版本通常增长有限。也可配置自动清理超出窗口的文件。

11. 总结

  • 真因:404 不是“没缓存”,而是“源站删了旧文件”
  • 原则:内容哈希 + immutable + HTML 短缓存
  • 方法:/assets 聚合最近 N 个版本资源 + /versions 备份入口
  • 效果:零 404、缓存最优、秒级回滚、可观测、易维护
当发布频繁、会话长、需要极致稳定体验时,这套工程化方案能显著提升质量与口碑。

Read more

【前端实战】多进制奇偶校验检查器(HTML+CSS+JS)完整实现,附源码

【前端实战】多进制奇偶校验检查器(HTML+CSS+JS)完整实现,附源码

在数字通信、数据传输及嵌入式开发中,奇偶校验是一种简单高效的差错检测方法,通过判断二进制数据中“1”的个数为奇数或偶数,快速校验数据是否存在传输错误。日常开发中,我们常需要对不同进制(二进制、八进制、十进制、十六进制)的数字进行奇偶校验,手动计算繁琐且易出错。 今天就给大家分享一款纯前端实现的「多进制奇偶校验检查器」,支持4种常用进制切换、自动识别进制前缀(如0x、0o、0b)、偶校验/奇校验可选,无需后端依赖,打开浏览器即可使用。同时拆解核心代码逻辑,适合前端新手练习DOM操作、正则验证及进制转换相关知识点。 先看效果 运行后 一、工具核心功能介绍 这款多进制奇偶校验检查器聚焦“便捷、精准、易用”,核心功能如下,覆盖日常开发中的奇偶校验场景: * 多进制支持:兼容二进制(2)、八进制(8)、十进制(10)、十六进制(16),可自由切换 * 智能前缀识别:

从2025看2026前端发展趋势

🎨 从2025看2026前端发展趋势 一、📌 核心前言(2025铺垫→2026展望) 2025年前端行业已完成“基础成熟化”:Vue3、React18成为主流,TypeScript全面普及,工程化流程趋于完善,AI工具开始渗透开发环节,但也暴露了痛点——开发效率不均衡、跨端体验不一致、AI与业务结合浅显、性能优化门槛高。 ✨ 核心趋势:2026年前端将从「基础成熟」走向「深度融合」,重点围绕「AI原生开发」「跨端统一」「性能极致」「工程化提效」四大方向突破,同时Node.js等底层工具的升级(如2026年Node.js新特性)将进一步推动前端向全栈化、平台化转型。 二、✍️ 五大核心趋势(手绘重点·结合2025现状) 1. AI原生开发:从“辅助工具”到“核心生产力” 🤖(最重磅) (1)2025现状 2025年,前端AI工具多为“辅助层面”

Qt 前后端通信(QWebChannel Js / C++ 互操作):原理、示例、步骤解说

Qt 前后端通信(QWebChannel Js / C++ 互操作):原理、示例、步骤解说

Qt 提供的 QWebEngineView 是一个基于 Chromium 内核的浏览器组件,通过它,开发者可以使用 HTML、CSS、JavaScript 等技术开发 Web 页面并呈现在 Qt 桌面应用中,但与开发纯 Web 页面不同的是,这些页面通常需要和 应用中的其他组件交互,例如获取后端数据进行渲染、将前端用户指令传达给后端执行等,这将不可避免地涉及到前端 Js 和 后端 C++ 之间的交互问题,而 Qt 为此给出的解决方案就是 QWebChannel,通过 QWebChannel 前端 Web 页面和与后端 C++ 程序实现自然而顺畅的交互,甚至前后端的操作风格都极为一致。本文我们将细致地介绍QWebChannel 前后端交互的原理,通过四个详实的示例程序讲解每一步重要的操作步骤,通过本文,你将对 QWebChannel 有一个全面而深入的了解。 1. 工作原理

如何实现 Web 触发后的“离线”升级?Systemd 异步机制与 A/B 状态机切换详解

目录 利用 Systemd Path 单元实现可靠系统升级 —— 支持 Web 接口触发且父进程退出后仍可继续执行 1. 背景与目标 2. 核心设计原则 3. 系统架构概览 4. 详细实现 4.1 升级脚本(独立执行单元) 4.2 Systemd 单元配置 4.3 Web 接口实现(FastAPI 示例) 5. 为何父进程退出不影响升级? 进程关系图 6. 增强可靠性建议 6.1 使用持久化触发目录 6.2 添加升级状态查询接口 6.3 升级脚本增加锁机制 7. 总结 AB 升级详解:基于软链接与配置切换的双环境热升级方案 1.