如何使用 js 统计访问量及网站运行时间

我打算用思源的 Docker 发布功能搭建博客,但不知如何统计访问量。能否提供一段 JS 代码,实现记录访问量和网站运行时间,并将这些信息显示在侧边栏?另外,希望代码存储的数据能通过 S3 同步或打包。

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    26030 引用 • 108019 回帖 • 1 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    10000 引用 • 45450 回帖 • 73 关注

相关帖子

被采纳的回答
  • wilsons 1 1 赞同

    写了一个代码,但不知你说的侧边栏是指放哪?感觉放不下,所以放状态栏了。

    另外,手机版也不知道哪里有位置显示,所以暂不支持。

    仅供参考。

    image.png

    // 统计网站访问量和运行时间 (async ()=>{ // api地址,最后不要加 / const apiUrl = 'http://127.0.0.1:6806'; // api token 在设置->关于中查看 const apiToken = ''; // 初始化数据 const initData = { // 网站总访问量 total: 0, // 网站运行初始日期 startDay: '2025-04-13' }; // 定义统计信息显示模板 const tongjiTpl = `总访问量:{total}&nbsp;&nbsp;网站运行:{runningDays}天`; // 已统计的跳过 if(document.querySelector('#status .site__tongji')) return; // 记录初始访问量 const initTotal = initData.total || 0; // 延迟等待数据加载和同步 await sleep(1500); // 获取置顶数据,格式 {"total":0, "startDay":''} let data = await getFile('/data/storage/site_tongji.json'); data = JSON.parse(data||'{}'); if(data.code && data.code !== 0) data = {}; data = {...initData, ...data}; // 仅网站版和发布服务版才统计 if(siyuan.config.readonly && isBrowser()) { // 当不存在total字段时初始化 if(!data.total) data.total = 0; // 当总数小于初始化值时,直接赋值为初始化的值 if(data.total < initTotal) data.total = initTotal; // 网站访问+1 data.total++; // 存储网站访问数据 if(data.total > 0) putFile('/data/storage/site_tongji.json', JSON.stringify(data, null, 4)); } // 获取网站运行时间 const runningDays = calculateRunningDays(data); // 状态栏显示统计信息 showStatusMsg(tongjiTpl.replace('{total}', data.total).replace('{runningDays}', runningDays)); // 计算网站运行时间(单位:天) function calculateRunningDays(data) { // 获取当前日期并重置时间为 00:00:00 const currentDate = new Date(); resetTime(currentDate); // 解析初始日期并重置时间为 00:00:00 const startDate = new Date(data.startDay); if (isNaN(startDate.getTime())) { return 1; } resetTime(startDate); // 计算时间差(毫秒) const timeDifference = currentDate - startDate; // 转换为天数 const daysDifference = Math.floor(timeDifference / (1000 * 60 * 60 * 24)); return daysDifference + 1; } function resetTime(date) { date.setHours(0, 0, 0, 0); // 设置时间为 00:00:00.000 return date; } // 状态栏输出 function showStatusMsg(html) { const statusMsg = document.querySelector('#status .status__msg'); if(!statusMsg) return; const tongji = document.querySelector('#status .site__tongji'); if(tongji) tongji.remove(); const style = ` color: var(--b3-theme-on-surface); white-space: nowrap; text-overflow: ellipsis; overflow: hidden; padding-left: 5px; font-size: 12px; `; html = `<div class="site__tongji" style="${style}">${html}</div>`; statusMsg.insertAdjacentHTML('beforebegin', html); } function isBrowser() { return !navigator.userAgent.startsWith("SiYuan") || navigator.userAgent.indexOf("iPad") > -1 || (/Android/.test(navigator.userAgent) && !/(?:Mobile)/.test(navigator.userAgent)); } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // 获取文件 async function getFile(path) { return fetch("/api/file/getFile", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ path, }), }).then((response) => { if (response.ok) { return response.text(); } else { throw new Error("Failed to get file content"); } }).catch((error) => { console.error(error); }); } // 存储文件,支持创建文件夹,当isDir true时创建文件夹,忽略文件 async function putFile(path, content = '', isDir = false) { const formData = new FormData(); formData.append("path", path); formData.append("isDir", isDir) formData.append("file", new Blob([content])); const result = await fetch(apiUrl+"/api/file/putFile", { // 写入js到本地 method: "POST", headers: { "Authorization": "token " + apiToken // 添加 Authorization 头 }, body: formData, }); const json = await result.json(); return json; } })();

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • 51LA 统计可以,并支持显示简单统计面板,由于第三方统计,都免去打包的麻烦了。

  • siyuan100861186 1 1 赞同

    有一个嵌入式的程序,umami,这个直接嵌入网站就可以统计访问信息了

  • wilsons 1 1 赞同

    写了一个代码,但不知你说的侧边栏是指放哪?感觉放不下,所以放状态栏了。

    另外,手机版也不知道哪里有位置显示,所以暂不支持。

    仅供参考。

    image.png

    // 统计网站访问量和运行时间 (async ()=>{ // api地址,最后不要加 / const apiUrl = 'http://127.0.0.1:6806'; // api token 在设置->关于中查看 const apiToken = ''; // 初始化数据 const initData = { // 网站总访问量 total: 0, // 网站运行初始日期 startDay: '2025-04-13' }; // 定义统计信息显示模板 const tongjiTpl = `总访问量:{total}&nbsp;&nbsp;网站运行:{runningDays}天`; // 已统计的跳过 if(document.querySelector('#status .site__tongji')) return; // 记录初始访问量 const initTotal = initData.total || 0; // 延迟等待数据加载和同步 await sleep(1500); // 获取置顶数据,格式 {"total":0, "startDay":''} let data = await getFile('/data/storage/site_tongji.json'); data = JSON.parse(data||'{}'); if(data.code && data.code !== 0) data = {}; data = {...initData, ...data}; // 仅网站版和发布服务版才统计 if(siyuan.config.readonly && isBrowser()) { // 当不存在total字段时初始化 if(!data.total) data.total = 0; // 当总数小于初始化值时,直接赋值为初始化的值 if(data.total < initTotal) data.total = initTotal; // 网站访问+1 data.total++; // 存储网站访问数据 if(data.total > 0) putFile('/data/storage/site_tongji.json', JSON.stringify(data, null, 4)); } // 获取网站运行时间 const runningDays = calculateRunningDays(data); // 状态栏显示统计信息 showStatusMsg(tongjiTpl.replace('{total}', data.total).replace('{runningDays}', runningDays)); // 计算网站运行时间(单位:天) function calculateRunningDays(data) { // 获取当前日期并重置时间为 00:00:00 const currentDate = new Date(); resetTime(currentDate); // 解析初始日期并重置时间为 00:00:00 const startDate = new Date(data.startDay); if (isNaN(startDate.getTime())) { return 1; } resetTime(startDate); // 计算时间差(毫秒) const timeDifference = currentDate - startDate; // 转换为天数 const daysDifference = Math.floor(timeDifference / (1000 * 60 * 60 * 24)); return daysDifference + 1; } function resetTime(date) { date.setHours(0, 0, 0, 0); // 设置时间为 00:00:00.000 return date; } // 状态栏输出 function showStatusMsg(html) { const statusMsg = document.querySelector('#status .status__msg'); if(!statusMsg) return; const tongji = document.querySelector('#status .site__tongji'); if(tongji) tongji.remove(); const style = ` color: var(--b3-theme-on-surface); white-space: nowrap; text-overflow: ellipsis; overflow: hidden; padding-left: 5px; font-size: 12px; `; html = `<div class="site__tongji" style="${style}">${html}</div>`; statusMsg.insertAdjacentHTML('beforebegin', html); } function isBrowser() { return !navigator.userAgent.startsWith("SiYuan") || navigator.userAgent.indexOf("iPad") > -1 || (/Android/.test(navigator.userAgent) && !/(?:Mobile)/.test(navigator.userAgent)); } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // 获取文件 async function getFile(path) { return fetch("/api/file/getFile", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ path, }), }).then((response) => { if (response.ok) { return response.text(); } else { throw new Error("Failed to get file content"); } }).catch((error) => { console.error(error); }); } // 存储文件,支持创建文件夹,当isDir true时创建文件夹,忽略文件 async function putFile(path, content = '', isDir = false) { const formData = new FormData(); formData.append("path", path); formData.append("isDir", isDir) formData.append("file", new Blob([content])); const result = await fetch(apiUrl+"/api/file/putFile", { // 写入js到本地 method: "POST", headers: { "Authorization": "token " + apiToken // 添加 Authorization 头 }, body: formData, }); const json = await result.json(); return json; } })();
    1 回复
  • CongSec

    可以一直显示吗?刚开始访问的时候就可以显示出来,但是过了一分钟左右就消失了

    image.png

    1 回复
  • wilsons 1 14 评论

    可以,等下用新的 dom 显示就行,现在用的 status 公共消息区,可能 🈶 新消息覆盖了

    还有别的问题吗?一起改

    2 回复
    暂时没有发现什么问题了
    CongSec
    @CongSec 代码已更新,你再看看还有没有什么问题
    wilsons 1
    @wilsons 我发现,他在发布的时候并没有增加访问量
    CongSec
    @CongSec 你说的访问量是指什么?一般访问量指页面刷新,即每次刷新增加一次,和发布无关。 建议尽量一次性把问题描述清楚,不建议在论坛像 QQ 那样聊天方式交流。
    wilsons
    @wilsons 可我的目的是通过发布功能搭建博客的时候统计访问量,不知道能否解决
    CongSec
    @CongSec 先定义你的访问量是指什么?即什么时候数字增加?触发条件是什么?最重要的就是这个触发条件。
    wilsons
    @wilsons 就是别人通过我的发布功能访问我的博客,然后别人访问一次,对应的访问量增加 1
    CongSec
    @CongSec 我没用过 docker 版,你 docker 版有没有加代码片段?有没有验证是否 js 加载成功了?比如,加个 alert(1),看看是否能弹出等,有没有网址可以看看。你是想仅发布模式下才增加,编辑模式不增加吗?
    wilsons
    @wilsons 不一定要 docker 搭建的,你就在本地上的发布功能和 docker 的发布功能是一样的吧,如果不难的话,尽量仅在发布模式下才增加
    CongSec
    @CongSec OK 等下看
    wilsons
    @wilsons 感谢,我新创建一个服务器来提供你测试,http://8.146.199.199:6806/,密码为 123
    CongSec
    @CongSec 我发现问题了,发布服务下,所以写接口都是禁止的,即无法写入任何数据,自然计数也无法增加了。现在有两种方式:1 是能否调用你同 ip 下的 6806 接口,如果可以可以调用 6806 的接口写 2 如果 1 不行,可以把数据存储到在线,方式同我之前开发的一键访问手机伺服类似,看你选哪种方便?
    wilsons 1
    @wilsons 都行的,能方案一的话尽量方式 1
    CongSec
    @CongSec 改好了,按方案 1,代码已更新,同时那个测试网站代码也加进去了。发布服务测试:http://8.146.199.199:6808/ 用户 a 密码 1 非发布服务,仅查看,刷新不在更新访问数。
    wilsons 1
  • CongSec 3 评论

    今天起床发现,服务端访问量从 168 回归到 5,期间的过程我想是因为归零一次了,以下是服务端的日志:

    systemlog.zip

    还麻烦你增强下代码的健壮性,把归零的代码逻辑部分去掉;

    image.png

    你最近有做什么吗?先推测下可能的原因,这样才能针对的解决问题。大致方向是同步的锅,比如存储的统计数据,尚未同步成功时被执行了存储操作,还有如果客户端上开启了只读模式,如果尚未同步成功,可能会被重写数据。所以,现在做了以下几种限制:1 仅发布服务和浏览器访问才统计,2 网站加载时暂停 1.5 秒执行,等待数据同步完成 3 判断已存数据是否小于初始数据 4 数据只有大于 0 的时候才被存储
    wilsons 1
    @wilsons 我的使用场景主要如下:服务器挂载 docker 启动发布功能充当博客,另一边是我的本机电脑, 两者的数据同步方式是采用 s3 同步,我的本机电脑更改数据点击同步会自动同步到服务器的 docker 当中,刚开始的几天内可以正常使用,也就是今天起床时候出现了故障,我启动博客(服务端的发布功能)查看,发现那里的访问量是 5 个,而我的本机电脑的访问量为 168,是正常的,没过多久,我本机的访问量也变成了 5 了,因该是服务器同步下来的,具体原因尚未清楚
    CongSec
    @CongSec 这种场景其实是有问题的,首先你得保证 docker 和电脑都 30 秒同步一次,即使这样中间也会有 10 分钟左右的误差,可能造成 10 分钟内的数据被覆盖,建议用我的同步感知 js 代码,可以把这个时间缩短至 30 秒。但这都不是最佳方案,建议最佳方式在 docker 的思源空间 data 目录外添加个标志文件,比如 docker.lock,然后我在 js 里判断是否存在这个文件,只在存在这个文件时才写统计数据,只要不存在都仅只读。当然这个 docker.lock 也可以放到 data 内,然后用忽略文件忽略,不过这样较麻烦,不推荐。
    wilsons
  • CongSec

    刚才更新了代码,我就尝试了不断地刷新,发现访问量竟然变成了 2,但是当我再次想尝试通过不断刷新来进行复现的时候,发现不行,因该是有概率性会出现这种情况,此时我的本机电脑访问量并不是 2,所以因该不是同步原因造成的,对了,我的博客是上了阿里云的 DCDN(DCDN 支持 WebSocket 协议),不知道是否是这个造成的,使用 DCDN 可以将博客的访问时间由原来的 10 几秒提升到 1-2 秒,所以 DCDN 功能 不能移除

    以下是我的成功复现时的日志文件:systemlog.zip

    1 回复
    1 操作
    CongSec 在 2025-04-20 19:02:43 更新了该回帖
  • 有可能,你再过测试看看,现在不好说,你可以在本地测试,如果本地没问题,那就应该是 dcdn 的问题。

    1 回复
  • CongSec

    嗯,我现在基本确定是 DCDN 的问题了,刚才我用一个 python 脚本来并发请求我的博客,发现数据(原来的访问量)又回来了,而我的同步功能是关闭的,也就是说,排除同步的影响,以下是新增加的日志文件,不知道大佬还有办法解决不

    image.png

    1 回复
  • wilsons 1

    这并不能确定是 dcdn 的问题,你得用 Python 请求本地的 url 地址试试,然后看看是否有问题,先排除是并发问题,还是 dcdn 问题,如果 dcdn 问题,你可以给阿里云提工单,让帮忙分析可能的原因。另外,这个日志无用,除了显示请求时间啥的,什么有用信息都没有。

    不过,按理说,并发问题,最多产生误差,不会出现这样大幅度的归零。

请输入回帖内容 ...
CongSec
新手可以看我发的求助帖以及汇总帖子,很有帮助的!_! 网安笔记分享:http://congsec.xyz 北京

推荐标签 标签

  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3455 回帖 • 149 关注
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 450 关注
  • MySQL

    MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是最流行的关系型数据库管理系统之一。

    693 引用 • 537 回帖
  • Mac

    Mac 是苹果公司自 1984 年起以“Macintosh”开始开发的个人消费型计算机,如:iMac、Mac mini、Macbook Air、Macbook Pro、Macbook、Mac Pro 等计算机。

    167 引用 • 597 回帖
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    173 引用 • 414 回帖 • 363 关注
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 677 关注
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    91 引用 • 59 回帖 • 4 关注
  • 安装

    你若安好,便是晴天。

    132 引用 • 1184 回帖 • 1 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    947 引用 • 1460 回帖 • 2 关注
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    142 引用 • 442 回帖
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 503 关注
  • JRebel

    JRebel 是一款 Java 虚拟机插件,它使得 Java 程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。

    26 引用 • 78 回帖 • 675 关注
  • H2

    H2 是一个开源的嵌入式数据库引擎,采用 Java 语言编写,不受平台的限制,同时 H2 提供了一个十分方便的 web 控制台用于操作和管理数据库内容。H2 还提供兼容模式,可以兼容一些主流的数据库,因此采用 H2 作为开发期的数据库非常方便。

    11 引用 • 54 回帖 • 672 关注
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 559 关注
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖 • 1 关注
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 438 关注
  • 快应用

    快应用 是基于手机硬件平台的新型应用形态;标准是由主流手机厂商组成的快应用联盟联合制定;快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台;以平台化的生态模式对个人开发者和企业开发者全品类开放。

    15 引用 • 127 回帖 • 4 关注
  • 星云链

    星云链是一个开源公链,业内简单的将其称为区块链上的谷歌。其实它不仅仅是区块链搜索引擎,一个公链的所有功能,它基本都有,比如你可以用它来开发部署你的去中心化的 APP,你可以在上面编写智能合约,发送交易等等。3 分钟快速接入星云链 (NAS) 测试网

    3 引用 • 16 回帖 • 1 关注
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    125 引用 • 585 回帖 • 1 关注
  • RESTful

    一种软件架构设计风格而不是标准,提供了一组设计原则和约束条件,主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    30 引用 • 114 回帖 • 1 关注
  • DevOps

    DevOps(Development 和 Operations 的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。

    59 引用 • 25 回帖
  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    162 引用 • 529 回帖 • 5 关注
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    45 引用 • 114 回帖 • 172 关注
  • Anytype
    3 引用 • 31 回帖 • 25 关注
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    34 引用 • 37 回帖 • 555 关注
  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    209 引用 • 2040 回帖 • 1 关注