因为如果只存在浏览器中(比如使用 localStorage),每个用户访问时看到的都只是自己的访问计数,而不是网站的总访问量。

htm 网页总访问次数 代码
(图片来源网络,侵删)

下面我将为您详细解释实现原理,并提供从简单到专业的多种代码方案。


核心原理

  1. 前端:用户访问你的网页时,浏览器会加载一个包含 HTML、CSS、JavaScript 的页面。
  2. JavaScript:页面加载后,一个 JavaScript 函数会被触发。
  3. API 请求:这个 JS 函数会向后端服务器发送一个请求,“嘿,服务器,有人访问了我的网站,请帮我更新一下访问计数。”
  4. 后端处理
    • 服务器收到请求后,会连接到数据库。
    • 在数据库中,找到存储访问次数的那个记录(比如一个名为 visitors 的表,里面有一个 count 字段)。
    • count 的值加 1。
    • 将新的 count 值保存回数据库。
    • 将新的 count 值作为响应返回给前端。
  5. 前端显示:前端的 JavaScript 接收到服务器返回的新计数值,并将其动态地显示在网页的指定位置。

关键组件:

  • 前端: HTML + JavaScript
  • 后端: 服务器(可以是 Node.js, Python, PHP, Java 等)
  • 数据库: 用于持久化存储访问次数(可以是 Redis, MySQL, MongoDB 等)

使用第三方统计服务(最简单、最推荐)

对于绝大多数个人博客或小型网站,不需要自己搭建后端,直接使用成熟的第三方服务是最佳选择,它们不仅提供访问次数,还提供更丰富的用户行为分析。

推荐服务:

htm 网页总访问次数 代码
(图片来源网络,侵删)
  • Google Analytics (谷歌分析):行业标准,功能强大,完全免费。
  • Clarity (微软 Clarity):免费,提供会话录制和热力图,非常直观。
  • 不蒜子 (busuanzi.ibruce.info):一个轻量、免费、无需注册的极简计数器服务,非常适合只想显示访问次数的场景。

示例:使用“不蒜子”服务

这是最简单的纯 HTML/CSS/JS 方案,你甚至不需要自己的服务器。

  1. 在你的 HTML 文件中,在你想显示访问次数的地方(例如页脚)添加以下代码:
<!-- 显示本站总访问量 PV -->
<span id="busuanzi_container_site_pv">
    本站总访问量 <span id="busuanzi_value_site_pv"></span> 次
</span>
<!-- 显示本站总访客数 UV -->
<span id="busuanzi_container_site_uv">
    本站总访客数 <span id="busuanzi_value_site_uv"></span> 人
</span>
  1. 在 HTML 的 <head><body> 底部,添加不蒜子的 JavaScript 脚本:
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

就这么简单! 当你的页面加载时,这个脚本会自动请求不蒜子的服务器,获取并显示你网站的 PV (Page View, 页面浏览量) 和 UV (Unique Visitor, 独立访客数)。


使用 Firebase(无服务器方案,非常灵活)

如果你不想写后端代码,但希望数据存储在自己的账户中,Firebase 是一个绝佳的选择,它提供了免费的额度,足够小型项目使用。

htm 网页总访问次数 代码
(图片来源网络,侵删)

步骤:

  1. 创建 Firebase 项目

    • 访问 Firebase 控制台,用 Google 账号登录。
    • 创建一个新项目。
    • 在项目中,启用 "Firestore Database"(云数据库),选择 "测试模式" 以便快速开发。
    • 创建一个集合 (Collection),比如命名为 counters,并在其中创建一个文档 (Document),命名为 visits,在这个文档里添加一个字段,count,初始值设为 0
  2. 配置网页

    • 在 Firebase 控制台的 "项目设置" -> "常规" 页面,找到你的 Web App SDK 配置,复制它。
    • 在你的 HTML 文件中,引入 Firebase SDK 和你的配置信息。
  3. 编写 HTML 和 JavaScript 代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">访问次数统计</title>
    <!-- 1. 引入 Firebase 核心库和 App 库 -->
    <script src="https://www.gstatic.com/firebasejs/9.15.0/firebase-app-compat.js"></script>
    <script src="https://www.gstatic.com/firebasejs/9.15.0/firebase-firestore-compat.js"></script>
    <!-- 2. 在这里粘贴你的 Firebase 配置 -->
    <script>
      const firebaseConfig = {
        apiKey: "YOUR_API_KEY",
        authDomain: "YOUR_AUTH_DOMAIN",
        projectId: "YOUR_PROJECT_ID",
        storageBucket: "YOUR_STORAGE_BUCKET",
        messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
        appId: "YOUR_APP_ID"
      };
      // 初始化 Firebase
      firebase.initializeApp(firebaseConfig);
      const db = firebase.firestore();
    </script>
</head>
<body>
    <h1>欢迎访问我的网站</h1>
    <p>总访问次数: <strong id="visit-count">加载中...</strong></p>
    <script>
        // 获取显示计数的元素
        const visitCountElement = document.getElementById('visit-count');
        // 获取 Firestore 数据库的引用
        const visitsRef = db.collection('counters').doc('visits');
        // 使用事务 (Transaction) 来确保计数的原子性
        // 防止在高并发时计数出错
        db.runTransaction(transaction => {
            return transaction.get(visitsRef).then(doc => {
                // 如果文档不存在,则创建它,初始值为 1
                // 如果文档存在,则获取当前值并加 1
                const newCount = (doc.data() ? doc.data().count : 0) + 1;
                transaction.update(visitsRef, { count: newCount });
                return newCount;
            });
        }).then(newCount => {
            // 更新页面上的显示
            visitCountElement.textContent = newCount;
        }).catch(error => {
            console.error("Error updating visit count: ", error);
            visitCountElement.textContent = "无法加载";
        });
    </script>
</body>
</html>

传统后端 + 数据库方案(最专业、最可控)

如果你有自己的服务器,或者想学习完整的全栈开发,这是最标准的做法,这里以 Node.js + Express + MongoDB 为例。

后端代码 (Node.js)

你需要一个 package.json 文件,并安装 expressmongodb

npm init -y
npm install express mongodb

创建一个 server.js 文件:

// server.js
const express = require('express');
const { MongoClient, ServerApiVersion } = require('mongodb');
const app = express();
const port = 3000;
// --- MongoDB 配置 ---
const uri = "mongodb://localhost:27017"; // 你的 MongoDB 连接字符串
const client = new MongoClient(uri, {
  serverApi: {
    version: ServerApiVersion.v1,
    strict: true,
    deprecationErrors: true,
  }
});
let visitsCollection;
// 连接到 MongoDB
async function run() {
  try {
    await client.connect();
    console.log("成功连接到 MongoDB!");
    // 访问数据库和集合
    const database = client.db("myWebsiteDB");
    visitsCollection = database.collection("visits");
    // 确保计数文档存在
    await visitsCollection.updateOne(
      { _id: "total_visits" }, // 查询条件
      { $setOnInsert: { count: 0 } }, // 如果不存在则插入
      { upsert: true } // 如果文档不存在则插入
    );
  } catch (err) {
    console.error(err);
  }
}
run().catch(console.dir);
// --- API 路由 ---
// 端点:增加访问次数
app.post('/api/increment-visits', async (req, res) => {
  try {
    const result = await visitsCollection.updateOne(
      { _id: "total_visits" },
      { $inc: { count: 1 } } // 使用 $inc 原子操作将 count 字段加 1
    );
    // 获取更新后的最新计数
    const doc = await visitsCollection.findOne({ _id: "total_visits" });
    res.status(200).json({ count: doc.count });
  } catch (error) {
    res.status(500).json({ error: "增加访问次数失败" });
  }
});
// 端点:获取访问次数
app.get('/api/get-visits', async (req, res) => {
  try {
    const doc = await visitsCollection.findOne({ _id: "total_visits" });
    if (doc) {
      res.status(200).json({ count: doc.count });
    } else {
      res.status(404).json({ error: "未找到访问次数记录" });
    }
  } catch (error) {
    res.status(500).json({ error: "获取访问次数失败" });
  }
});
app.listen(port, () => {
  console.log(`服务器正在 http://localhost:${port} 上运行`);
});

前端代码 (HTML + JavaScript)

创建一个 index.html 文件,它将从后端 API 获取数据。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">访问次数统计</title>
</head>
<body>
    <h1>欢迎访问我的网站</h1>
    <p>总访问次数: <strong id="visit-count">加载中...</strong></p>
    <script>
        const visitCountElement = document.getElementById('visit-count');
        const API_URL = 'http://localhost:3000/api/get-visits';
        // 页面加载时获取访问次数
        window.addEventListener('DOMContentLoaded', () => {
            fetchVisits();
        });
        // 页面关闭或刷新时,向服务器发送请求增加访问次数
        // 注意:这个方法不是 100% 可靠的,但作为演示足够了
        window.addEventListener('beforeunload', () => {
            incrementVisits();
        });
        async function fetchVisits() {
            try {
                const response = await fetch(API_URL);
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                const data = await response.json();
                visitCountElement.textContent = data.count;
            } catch (error) {
                console.error("无法获取访问次数:", error);
                visitCountElement.textContent = "无法加载";
            }
        }
        async function incrementVisits() {
            try {
                await fetch(API_URL, { method: 'POST' });
            } catch (error) {
                console.error("无法增加访问次数:", error);
            }
        }
    </script>
</body>
</html>

如何运行:

  1. 确保你的电脑上安装并运行了 MongoDB。
  2. 运行 node server.js 启动后端服务器。
  3. 在浏览器中打开 index.html 文件。

总结与选择建议

方案 优点 缺点 适用场景
第三方服务 最简单,无需后端,功能强大,免费 数据在第三方,有隐私顾虑,依赖服务可用性 绝大多数个人博客、企业官网、小型项目首选方案
Firebase 无需自己管理服务器,免费额度足够,数据在自己账户 学习成本略高,长期大量数据可能产生费用 中小型项目,希望有数据自主权,不想写后端代码的开发者。
传统后端+数据库 最专业,完全自主可控,性能高,可扩展性强 需要自己搭建和维护服务器,开发周期长,成本高 大型网站、对数据安全和性能有极高要求的专业项目。

对于初学者或快速实现需求,强烈推荐方案一(不蒜子),如果你想深入学习全栈开发,方案三(Node.js + MongoDB) 是一个很好的实践项目。