应用上线后, 如何通知用户刷新来更新当前页面(实践方法总结)

关键词:静态资源更新、页面版本更新

这个话题非常的有意思,问题的答案是比较开发的,这里仅代表作者本人的个人经验来做回答。 当然也可以自行去搜集掘金上的大佬们的博文。

首先第一个问题

用户在没有页面刷新的情况下, 如何去感知前端静态资源已经发生了更新?

首先要做静态资源版本管理。 这个版本直接给到 html 模板即可, 其他 link 打包的资源还是以哈希 code 作为文件名称后缀。

就类似于这样子的

lua 复制代码
xxx.1.0.0.html --> vender.hash_1.js、 vender.hash_2.js、 vender.hash_3.js、vender.hash_1.css

xxx.1.0.1.html --> vender.hash_a.js、 vender.hash_b.js、 vender.hash_c.js、vender.hash_d.css

如何主动推送给客户端

这个实现方式就非常的多了,我这里建议让服务端来做处理

因为我们前端静态资源打包之后, 大多数会上传到云存储服务器上, 或者甚至是 服务器本地 也行。 这个时候, 后端给一个定时任务, 比如 1 分钟去执行一次, 看看是否有新的 html 版本的内容生成。 如果有新的 html 版本内容生成, 且当前用户访问的还是旧版本, 那么直接发一个服务端信息推送即可(SSE 允许服务器推送数据到浏览器)。

实现也非常简单:

下面是一个用 Node.jsServer-Sent Events (SSE)实现的简单示例。这个例子包括了一个用于服务端推送事件的 HTTP 服务器,以及一个简单的静态 HTML 版本检查机制:

首先,我们可以使用 Express.js 框架进行服务端编码:

javascript 复制代码
const express = require("express");
const fs = require("fs");
const path = require("path");

const app = express();
const PORT = 3000;

// 存储连接的客户端
const clients = [];

// 假设静态资源在 'public' 目录下,'index.html' 变动作为版本更新的代理
const STATIC_DIR = path.join(__dirname, "public");
const HTML_FILE = path.join(STATIC_DIR, "index.html");
let currentHtmlVersion = fs.readFileSync(HTML_FILE, "utf-8");

// 中间件提供静态文件
app.use(express.static(STATIC_DIR));

// SSE端点,用于发送消息到客户端
app.get("/events", (req, res) => {
  res.writeHead(200, {
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache",
    Connection: "keep-alive", // 保持连接
  });

  // 添加此客户端到数组
  clients.push(res);

  // 当客户端关闭连接时移除监听
  req.on("close", () => {
    clients.splice(clients.indexOf(res), 1);
  });
});

// 路由返回当前HTML版本
app.get("/current-version", (req, res) => {
  res.send(currentHtmlVersion);
});

// 启动服务器
const server = app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
  checkForUpdatesPeriodically();
});

// 定时任务,每分钟检查`index.html`是否更新
function checkForUpdatesPeriodically() {
  setInterval(() => {
    let newHtmlVersion = fs.readFileSync(HTML_FILE, "utf-8");
    if (newHtmlVersion !== currentHtmlVersion) {
      currentHtmlVersion = newHtmlVersion;
      notifyAllClients();
    }
  }, 60000); // 检查周期:1分钟
}

// 通知所有连接的客户端
function notifyAllClients() {
  clients.forEach((client) => client.write(`data: update\n\n`));
}

这段代码创建了一个简单的服务器,该服务器每一分钟读取一次index.html的内容,并检查是否有更新。如果发现更新,它会通过 SSE 发送消息给所有连接的客户端,通知它们页面已更新。

接下来,客户端需要监听来自服务器的事件,并相应地采取行动:

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Page Title</title>
  </head>
  <body>
    <h1>Content of the Page</h1>
    <script>
      // 创建SSE连接到服务器的/events路径
      const evtSource = new EventSource("/events");

      evtSource.onmessage = function (event) {
        // 服务器发送更新通知时,接收事件
        if (event.data === "update") {
          alert("新版本页面已可用,即将为您刷新!");
          window.location.reload();
        }
      };
    </script>
  </body>
</html>

这样做成本是最低的, 甚至可以说是一劳永逸。 前端是没有任何负债, 没有任何性能问题。

那是否还有别的处理方式呢? 当然是有的。

  1. WebSockets

通过 WebSocket 连接,服务器可以实时地向客户端发送消息,包括静态资源更新的通知。收到消息后,客户端可以采取相应的措施,比如显示一个提示信息让用户选择是否重新加载页面。

  1. Service Workers(推荐)

Service workers 位于浏览器和网络之间,可以控制页面的资源缓存。它们也可用于检测资源更新,当检测到静态资源更新时,可以通过推送通知或在网站上显示更新提示。

  1. 轮询

客户端用 JavaScript 定时发送 HTTP 请求到服务器,查询版本信息。如果检测到新版本,可以提醒用户或自动刷新资源。

在绝大多数情况下,使用 Service Workers 可能是最稳妥的做法,因为它不仅提供了资源缓存和管理的能力,而且也可以在后台做资源更新的检查,即使用户没有开启网页也能实现通知和更新的功能。

社区上有很多相关文章, 他们的处理办法基本上也逃不开以上几种方式

比如这篇高赞文档: juejin.cn/post/718545.... 点赞量有 1.8k, 实现的方式是前端轮询。

这篇文章也不错: juejin.cn/post/733025.... 实现方式是通过 websocket.

相关推荐
Pedantic6 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘6 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆6 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师7 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆7 小时前
VSCode自动格式化三要素
前端
爱勇宝8 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen9 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user205855615181311 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode11 小时前
Redis 在生产项目的使用
前端·后端