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

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

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

首先第一个问题

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

首先要做静态资源版本管理。 这个版本直接给到 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.

相关推荐
蜗牛快跑2135 分钟前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy6 分钟前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
涔溪1 小时前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
用户3157476081351 小时前
成为程序员的必经之路” Git “,你学会了吗?
面试·github·全栈
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与1 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun1 小时前
CSS样式实现3D效果
前端·css·3d
咔咔库奇1 小时前
ES6进阶知识一
前端·ecmascript·es6
渗透测试老鸟-九青2 小时前
通过投毒Bingbot索引挖掘必应中的存储型XSS
服务器·前端·javascript·安全·web安全·缓存·xss