今天给博客加了「阅读次数」。
听起来是个很小的功能,但做下来有几个决定挺值得记的。
一、为什么不用现成的统计服务
最省事的做法是挂一段别人的统计脚本 —— 百度统计、Google Analytics 那种,挂上去就自动告诉你每篇文章被看了几次。
我没用,两个原因。
第一,那些脚本是从别人服务器加载的。 Google 的脚本在国内经常转圈甚至根本加载不出来,页面上就会卡着一个一直不结束的请求。而且我前几天刚把「不用第三方」当原则,转头就挂一个进来,说不过去。
第二,它们要收集访客信息。 加了那段脚本,每个来看我博客的人,设备、IP、看了什么、停了多久,都会被记到别人公司的数据库里。
我一个初中生的小博客,不值当让来看的人付出这个。
二、为什么用 PHP,不用 Node
我服务器上本来就跑着一个 Node 项目(HomeChat),顺手写个 Node 接口也行。
但 PHP 有个 Node 没有的好处:不需要一直开着进程。
| Node | PHP | |
|---|---|---|
| 平时 | 一个进程一直在后台跑着 | 不在 |
| 占内存 | 一直占着 | 有请求才起来,干完就退 |
| 崩了 | 网站少个功能,得想办法自动重启 | 下次请求自动重来 |
| 开机自启 | 得单独配 | 不用管 |
我这台机器只有 2G 内存,能省一点是一点。
三、没建数据库,用一个 .php 文件当数据库
说起来有点土,但很好用。
我要存的东西就长这样:
{ "hits": { "/posts/first-post/": 13, "/posts/second-post/": 8 }, "seen": { "访客哈希|/posts/first-post/": 1759600000 }, "rate": { "访客哈希": [1759600000, 3] }}一共就十几篇文章,最坏也就几百条。为这个装一个 MySQL(常驻内存 400 兆)纯属浪费。
所以直接写进一个文件。
关键在文件名
文件叫 _data.php,内容的第一行是:
<?php exit; ?>这一行是干什么的?
那个文件放在网站目录里,别人是能猜到网址的。如果它叫 count.json,别人打开网址就能把整个数据库下载走。
但叫 .php 就不一样了 —— 别人访问的时候,服务器会去执行它,而不是把内容发出去。第一行 exit 的意思就是「到此为止」,后面那串 JSON 一个字都不会发出去。
同样的存储,换个后缀,从「谁都能下载」变成「谁看都是空白」。
比起去改 nginx 配置加一条「禁止访问这个文件」,这个办法不用改任何配置,也不会配错。
(当然,前提是服务器上装了 PHP。要是没装,nginx 会把它当普通文本发出来。所以我是先把 PHP 装好,再放这个文件的。)
四、防刷:同一个 IP 看同一篇,一小时只算一次
不设这个的话,我自己按着 F5 就能把阅读量刷到一万。
做法是把访客的 IP 加一点盐、算个哈希,然后记下「这个哈希在什么时候看过这个页面」。一小时之内再来,就不算了。
存的是哈希,不是原 IP。 这样万一哪天这个文件被人拿到了,也看不出谁是谁。
不过要老实说一句:这样会少算。
一个 WiFi 下十个人看同一篇文章,只算一次;同一个运营商的大内网里,可能几千人都算成一个。所以这个数字的意思是「大概有多少人看过」,不是精确的点击次数。
想看精确的也能做(记浏览器指纹),但那就是在追踪访客了。一个浏览量,不值当。
五、前端:一次请求把数字全拿回来
首页上摆着十几张文章卡片,每张都要显示阅读数。
最直接的写法是一张卡发一次请求。但那就是打开一次首页要发十几次 —— 我服务器带宽只有 5M,这属于自己给自己添堵。
所以改成:脚本先把页面上所有需要的路径收齐,合成一次发出去。
{ hit: "当前这一篇", // 记一笔 read: ["卡片1", "卡片2", …], // 顺便把这些的数字也给我 total: true // 顺便把全站总数也给我}服务器一次把三样都办了。
一个来回,不管页面上有多少个数字。
六、小设计:拿不到数字,就装作没有这个功能
如果服务器上的接口没装好,或者访客的网络把它拦了,会怎么样?
我的做法是:那些位置一开始全是藏起来的,拿到数字才显示。
- 接口好的时候 → 正常显示「128 次阅读」
- 接口不通的时候 → 这一项根本不出现
而不是留一个「0 次阅读」或者「NaN」在那儿碍眼。
原理简单到只有一条 CSS:
[data-views-path]:not([data-views-ready]) { display: none !important; }脚本把数字填进去之后,给这个元素加上 data-views-ready,它就冒出来了。
「优雅降级」这个词听着挺高级,其实意思就是:坏了也别让人看见。
七、统计页 vs 后台:我选了公开页面
本来想做个「后台」—— 加个密码、开个端口,只有我自己能看数据。
后来想了想,改成做一个公开的统计页。
理由是:
浏览量本来就是公开的。 每篇文章开头和底部都写着「被看了几次」,藏起来没有任何意义。
而做后台要多三个东西:密码、端口、防爆破。三个可能出错的地方,换来的是「只有我能看」—— 而我又没有什么需要藏的数据。
统计页还能顺便做点好看的:
全站总阅读 文章 平均每篇 1,234 17 篇 73
阅读排行1 ████████████████████ 博客搬进自己的服务器… 128 次2 ██████████ 今天把博客翻修了一遍… 64 次3 ████ 我做的第一个像样的东西… 26 次这个页面的骨架是构建的时候就写好的(谁也不知道数字是多少),数字是打开的时候现拿的。所以它既是个静态页面(快、不怕挂),又能显示实时数据。
没有后台,但该有的都有。
最后
今天做的其实是很多个「选哪条路」:
| 要干的事 | 选的路 | 为什么 |
|---|---|---|
| 存数据 | 一个 .php 文件 | 十几篇文章,不值得装 MySQL |
| 接口用什么语言 | PHP | 不用常驻进程,省内存 |
| 数据怎么不被人看 | 换个后缀 | 零配置,比改 nginx 简单 |
| 前端怎么省请求 | 合并成一次 | 5M 带宽经不起十几次请求 |
| 数据看板 | 公开页面 | 少三个出错的地方 |
这里面没有一个是「哪个技术更高级」,全是「我这个具体情况该怎么办」。
我觉得这才是真正难的地方 —— 会用一个技术不难,知道在这个场景下该不该用它才难。