打造极简网站流量统计小工具
背景
博客网站搭建完后,就可以开始博客写作了。当我们认真写完并发表一篇文章后,当然也希望知道有多少人阅读过,这就需要用到网站流量统计功能。
目前实现网站流量统计功能的平台和第三方产品,可选择范围非常多。比如Google和百度都是广泛使用的成熟平台,可以提供非常全面的数据统计功能。其他的,比如不蒜子
也是使用率很高的第三方产品。
在分析了各平台和产品的优缺点后,我发现自己其实想要的很简单,其实就两个要求:一是数据安全可控;二是功能简单,易于接入。基于这两方面的考虑,最终决定自己去构建一款轻量级的网站流量统计小工具。
选型思路
确定好走自研方向后,开始考虑一些技术选型方面的事项。
既然是自研,首先要考虑开发成本,其次是部署和运维成本。基于这些成本考虑,首先排除购买云主机进行独立部署的选项。那么剩下的只有提供无服务器服务的平台了。目前各大云平台几乎都提供Serverless
无服务计算产品,比如AWS Lambda,Azure Functions,Cloudflare Workers等。
由于我之前一直在用Cloudflare,对它的各个产品也比较熟悉,所以比较倾向于选择Workers来实现。另外,Workers还提供Wrangler Action,可以在提交代码到GitHub代码仓库时自动触发部署,整个过程完全实现自动化,极大的节省后续的部署和运维成本。
基于以上这些优点,最终确定了Node.js
+ Cloudflare Workers
+ GitHub Action
的选型组合。
功能实现
确定好技术选型后,再分析产品功能的实现思路。
整个流量统计工具包括前端JavaScript脚本和后端API服务,前端脚本命名为rain.js
,后端服务则由worker.js
实现。
前端实现
首先是前端JS脚本实现逻辑,流程如下:
- 页面加载脚本后触发执行统计函数。
- 在函数中,首先获取当前页面中所有样式为
.page_pv
的元素列表。 - 根据元素列表的长度进行判断并构建对应的请求报文,并请求后端API服务。
- 如果长度等于1,则默认是文章页的请求,站点PV加1,页面PV加1。
- 如果长度大于1,则默认是文章列表页的请求,站点PV加1。
- 除以上两种情况,则默认是其他页面的请求,站点PV加1。
- 根据请求响应结果,将统计数值添加到页面中。
核心实现代码如下:
//页面流量统计入口
async function count() {
const pagePVElems = document.querySelectorAll('.page_pv');
if(!pagePVElems) {
return;
}
const reqData = buildReqData(pagePVElems);
if(!reqData) {
return;
}
const reqDataStr = JSON.stringify(reqData);
const resData = await req(reqDataStr);
if(!resData) {
return;
}
const resDataStr = JSON.stringify(resData);
if(resData.data && resData.data.sitePV) {
const sitePVEl = document.querySelector('.site_pv');
sitePVEl.innerHTML = resData.data.sitePV;
}
if(resData.data && resData.data.pages) {
for(let i = 0; i < pagePVElems.length; i++) {
pagePVElems[i].innerHTML = resData.data.pages[i].pagePV;
}
}
}
后端实现
然后是后端API实现逻辑,流程如下:
- 接收到计数请求后,获取
User-Agent
,Referer
,Origin
等信息。 - 先计算站点PV。根据
Origin
从KV中获取当前站点PV数值,如果存在则加1,如果不存在则赋值1。 - 再计算页面PV,这里要分两种情况:
- 如果URL数量等于1,根据URL从KV中获取页面PV数值,如果存在则加1,如果不存在则赋值1。
- 如果URL数量大于1,根据URL从KV中获取页面PV数值,如果存在则不做操作,如果不存在则赋值0。
- 组装计算结果并返回。
核心实现代码如下:
//计数
async function count(request) {
let code = '200';
let message = 'OK';
let data = {};
const reqBody = await readReqBody(request);
if(!reqBody) {
return buildCountRes('400', 'request body is not exist', null);
}
const countType = reqBody.countType;
const urls = reqBody.urls;
if(!countType || !urls) {
return buildCountRes('400', 'count type or url array is not exist', null);
}
if(countType === '01') {
return buildCountRes(code, 'count type is 01, no count', null);
}
if(countType === '00') {
return buildCountRes(code, 'count type is 00, no count', null);
}
const ua = request.headers.get('User-Agent');
const ip = request.headers.get('CF-Connecting-IP');
const rf = request.headers.get('Referer');
const or = request.headers.get('Origin');
let sitePVKeyPrefix = 'sitePV:';
let siteUVKeyPrefix = 'siteUV:';
let pagePVKeyPrefix = 'pagePV:';
let pageUVKeyPrefix = 'pageUV:';
let sitePVKey = sitePVKeyPrefix + or.normalize();
let sitePVNum = await env.VIEWS.get(sitePVKey);
if(sitePVNum) {
sitePVNum = Number(sitePVNum) + 1;
} else {
sitePVNum = 1;
}
env.VIEWS.put(sitePVKey, sitePVNum.toString());
data.sitePV = sitePVNum;
if(countType === '10') {
if(urls) {
let tmpArr = [];
for(const el of urls) {
let pagePVKey = pagePVKeyPrefix + el.normalize();
let pagePVNum = await env.VIEWS.get(pagePVKey);
if(!pagePVNum) {
pagePVNum = 0;
}
let tmpObj = {
url: el,
pagePV: pagePVNum
}
tmpArr.push(tmpObj);
};
data.pages = tmpArr;
}
}
if(countType === '11') {
if(urls) {
let tmpArr = [];
let pagePVKey = pagePVKeyPrefix + urls[0].normalize();
let pagePVNum = await env.VIEWS.get(pagePVKey);
if(pagePVNum) {
pagePVNum = Number(pagePVNum) + 1;
} else {
pagePVNum = 1;
}
env.VIEWS.put(pagePVKey, pagePVNum.toString());
let tmpObj = {
url: urls[0],
pagePV: pagePVNum
}
tmpArr.push(tmpObj);
data.pages = tmpArr;
}
}
return buildCountRes(code, message, data);
}
以上就是前端脚本和后端服务的核心实现代码,如果想了解更多代码细节,请访问Gentle Rain了解更多。
效果展示
目前,这款轻量级网页流量统计工具已正式发布,最新版本为1.0.0。我把它名命为Gentle Rain
,其实也没有特别的原因,主要是在创建Workers服务的时候,系统自动生成了这个名字。我觉得还挺不错的,那就笑纳了。
说了这么多,让我们看看下面的效果图吧。当然,你也可以直接访问我的个人博客CRUDMAN进行阅读和体验。
看到这里,如果你也想给自己的独立博客网站加上专属的网页流量统计功能,欢迎访问Gentle Rain中文介绍,这里有更详细的应用接入指南。
最后,如果你觉得这个小工具还是有点用的话,欢迎Star
、Fork
、Watch
一键三连。
注:当前版本为1.0.0,只实现了PV统计功能,UV统计计划下一个版本实现,敬请期待。