umami 实现网站流量统计模块

umami 实现网站流量统计模块
amiracle前言
建站之后,很难没有统计网站访问人数的想法,本篇在 hexo 框架 + anzhiyu 主题环境下,利用 umami 0 成本实现网站流量统计,并实现统计模块。顺便说一下模块开发历程吧 (真是一波三折啊)
umami 统计工具感觉很 nice 啊,首先是 0 成本,然后你还能直接用它的 Umami Cloud 而不用部署自己的数据库,展示的数据也很全面,网页的 GUI 看着也是蛮舒服的
GUI 参考
写 umami 模块的过程也是挺坎坷的,遇到了很多坑。
准备工作
为了使用
umami,要先得到三样东西,website id,tracking code
和 api key,简单带过
首先在 umami 官网 注册账号,之后到控制台新增网站,然后打开右侧设置页面
可以看到 Website ID 和 Tracking code
为了统计网站数据,我们需要将 <script>
代码片段插入到网页的 <head>
里面,当有人访问网站时,该脚本会自动向 umami 发送数据以进行统计。在
anzhiyu 主题,主题的 _config.yml
文件中内置了插入接口,可以直接放在 inject.head。
1 | inject: |
测试是否可用,文件保存后,打开网站随便刷新几下。还是相当灵敏,这是在 umami 控制台看到的访问数据

api key
上述流程非常之简单啊,于是来到了下面的关键部分
获取数据
我不止想从 umami 网页上看到数据,还想在博客展示,那肯定要先拉取统计数据。然而 GPT 说要写 js,向服务器请求数据。啊?可我只是编程菜鸡啊,没学过 js 根本看不懂呐,怎么办 QAQ,那我只能浅学恶补一下 js 了
JavaScript 基础
网页三剑客之一的 JavaScript (js),是动态,解释型编程语言,负责网页的行为/交互逻辑,同时也常用于服务器和移动端的开发
机制
事件循环(Event loop) 是 JavaScript
的核心机制,解释了单线程 JS
如何处理同步任务和异步任务。在此机制下,任务执行顺序大致是
同步任务 -> 微任务 ->
一个宏任务 -> 微任务 ->
一个宏任务 …
,注意每个宏任务执行后都会清空微任务队列且同步任务优先级最高,如此直到队列为空
主线程遇到同步任务时会立刻执行直到完成,遇到异步任务时不会等待完成,即不会被其阻塞,会把任务交给游览器或 node.js 后台等外部环境处理(比如 I/O,定时器,网络请求),然后自己去执行后续任务。异步任务完成后,其回调被加入微任务或宏任务队列等待主进程去执行,这也就是异步执行的逻辑
运行
Node.js 是执行
javascript 代码的工具,在终端使用 node 执行 js 代码
1 | node file.js |
发起请求
通过 fetch 可以向服务器发起请求
1 | let res = await fetch("https://example.com"); |
GET 请求完整示例,比如 fetch octocat(据说是吉祥物) 的用户信息
1 | let URL = "https://api.github.com/users/octocat"; |
调用 fetch 会立刻执行网络请求并返回一个
promise
对象,而且主线程并不会等待请求的完成,会将等待网络请求的任务丢给别人,之后其走到
.then() 时会注册回调,.then()
里面的东西会也会异步执行
promise 对象有三种状态
pending,fulfilled 或
rejected,当状态变成 fulfilled/rejected
时,注册的 .then()/.catch()
回调会加入微任务队列,等待主线程执行
若能成功 fetch,会输出 JSON 格式内容,大概是
1 | 主线程已走到此处 |
可以发现很不合理的现象 ——
下面的语句更先执行。这正是因为主线程没有等待 fetch
执行完成,先去执行了后续任务也就是
console.log("主线程已走到此处"),当 promise
状态改变后才执行了 fetch 中的回调,输出了 json 数据
更现代化的写法是用 async funtion,在此函数中允许使用
await
来暂停函数内部的执行。具体来说,为何需要异步执行,因为服务器返回数据需要时间,为了不阻塞主进程,fetch
发起请求之后,函数的剩余部分会进入微任务队列,主线程会先去执行别的任务,等
promise
改变即服务器响应后,再执行该函数剩余部分,这样就有了更高的工作效率。
1 | (async () => { |
res.json() 前也需要 await
,此解析操作也是异步执行,没有会导致过早的执行
console.log(data)
此外,( lambda )();
是立即执行的匿名函数表达式(IIFE),=> 是 js
里匿名函数的写法,上述代码等价于
1 | async function work (){ |
拉取网站统计信息
详细接口可以参考 umami
docs,获取相关数据我们可以使用
Endpoint : ../websites/<website_Id>/stats
umami cloud
是官方提供所有用户的存储服务,若要使用则前缀设为
https://api.umami.is/v1 即可
接着要在请求头带上 api_key,另外可以带上
startAt & endAt 参数指定时间范围,js
代码如下,stAt/edAt 为时间戳(ms)
1 | const URL = "https://api.umami.is/v1"; |
若是自建数据库,并部署了 umami 实例,为获取数据库中的数据,上述代码中
URL 改成
http://<your-umami-instance>/api 即可,从 umami
获取到的 JSON 数据参考
1 | { |
一开始我理解错了文档,导致一直 fetch 不到信息,状态码 500。
官网写的是
Endpoint : GET /api/websites/:websiteId/stats,于是我就通过
Umami Cloud 的 https://api.umami.is/vi 去
fetch("https://api.umami.is/v1/api/websites/:websiteId/stats),但是根本就
fetch 不到啊,我一堆问号,问 ai 才知道,原来不应该写
/api,果然,去掉之后成功 fetch。
后来发现文档原来有 curl 的示例,然而因为
crul
不熟,所以我直接略过,导致调了半天,没仔细阅读文档导致的。
anzhiyu 统计模块
有了上述代码,我们就可以得到任意时间段的数据。我需要的是
今日人数, 今日访问, 昨日人数, 昨日访问, 本月访问, 本年访问,还要处理一下数据,代码如下
1 | const URL = "https://api.umami.is/v1"; |
node file.js 运行,输出如下
1 | { |
接着我在 themes\anzhiyu\layout\includes\page\about.pug
中找到了主题自带的 LA
统计模块,初看很晦涩,然而仔细研究一下代码,发现确实很晦涩,在 ai
的辅助下也是有点难看懂,不过没关系,只需要看懂部分关键逻辑,其他直接沿用就好,于是就有了下面的代码,主要是插入了上述代码,然后对原代码稍加修改最后加上
if/else 就大功告成了。
补充一下,pug 是一种生成 html
的模板语言,在 script(). 里引用 pug 变量
需要使用 #{},在修改 pug 文件后需要
hexo clean && hexo s 重新部署后网页才会改动。
注意 : 用户可以读到前端代码,因而 API_KEY
之类的东西不能直接明文写在前端比如 pug
里,应该定义在后端,在前端引用。
( 严格来说其实下面是 pug 代码,因为 highlight 不支持 pug,我搞了半天也没搞懂怎么弄,只能暂用 js 标签了 TAT )
1 | .author-content |
现在这个模块就差不多完工了,我们还需要在
themes\anzhiyu\_config.yml 中添加相应字段来启用
1 | # 51a统计配置 |
最后还需要借用 anzhiyu 佬的 LA 统计模块的前端,我最终在
themes\anzhiyu\source\css\_page\about.styl 找到了当
LA.enable 为 true
时会调用的前端代码,加上三行即可
1 | if (hexo-config('LA.enable')) { |
终于! 到这里就完工了,hexo clean && hexo s
重新部署就可以,效果图如下
注意 : Umami Cloud 数据存储时限大概为 6 个月,有需求可以自行部署数据库
写在最后
插曲
写 about.pug 时被 vsc
坑了,它竟然没标出语法错误,我没意识到直到肉眼观察到一个极其离谱的语法错误。调试这些错误,也是直接将我
about 页的 pv 干到了 500 多。要四了,愿天堂有能显示 pug 语法错误的
vsc
还遇到了一个非常诡异的情况,服务器端网站竟然和本地网站显示不一样?我无可奈何,hexo clean && hexo g
后重新上传也是不行。想到可能是代码写史了,没办法只能新建一个
TEMPblog 文件夹,然后重装一遍 HEXO&ANZHIYU
了,不过轻车熟路啊,几分钟就搞好了,重新 new page about 后发现,开启 LA
统计模块咋也有相同问题,百思不得解。
实在没办法了,只能去问万能的群 u 了,没想到啊没想到,群 u 直接把问题秒了
大概就是这样,好玄学啊,我从控制台没看到网页有缓存任何数据啊,不理解,不过群 u 真是见多识广%%%
于是不知道搞了多少小时 umami 统计模块终于完工了,最后实现的效果还是很好的🎉













