多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

GoatCounter 多域名统计指南:domain 不落库的架构限制与 path 注入聚合方案

GoatCounter 多域名统计指南:domain 不落库的架构限制与 path 注入聚合方案 数据分析后端【免费下载链接】goatcounterEasy web analytics. No tracking of personal data.项目地址https://gitcode.com/gh_mirrors/go/goatcounter点击查看免费下载GoatCounter 是一款“轻松上手、不追踪个人数据”的网页统计工具但它在数据模型上有一个容易被忽略的设计单次页面浏览pageview并不记录它来自哪个域名。本文基于仓库中的官方帮助文档 tpl/help/domains.md完整说明这一限制的形成原因与源码依据并给出两种实战方案——为每个子域名独立建站或将域名信息注入 path 实现单站聚合。读完本文你将掌握在 GoatCounter 中正确处理多域名、多子域名统计的完整配置方法与底层原理。核心限制GoatCounter 不存储页面浏览所属的域名官方文档在 tpl/help/domains.md 的开篇就直截了当地说明了这个设计事实GoatCounter doesnt store the domain a pageview belongs to; if you add GoatCounter to several (sub)domains then theres no way to distinguish between requests toa.example.com/pathandb.example.com/pathas theyre both recorded as/path.即GoatCounter 不存储 pageview 所属的域名。如果你的网站部署在多个子域名下同时接入同一个 GoatCounter 站点那么对a.example.com/path和b.example.com/path的请求都会被记录成同一个/path二者在统计上完全无法区分。这一点可以从仓库源码中得到印证。在数据接收端hit.go 中Hit结构体对 path 的定义为Path string db:- json:p,omitempty // 仅存在于 JSON 载荷中不落库为独立列db:-表示该字段不会作为独立数据库列存储而整个结构体中并没有Host、Domain之类的字段——也就是说命中记录在入库时根本没有保存来源域名。再看前端采集脚本 public/count.js 的get_path()实现var get_path function() { var loc location, c document.querySelector(link[relcanonical][href]) if (c) { // May be relative or point to different domain. var a document.createElement(a) a.href c.href if (a.hostname.replace(/^www\./, ) location.hostname.replace(/^www\./, )) loc a } return (loc.pathname loc.search) || / }它只取location.pathname location.search或同域名 canonical 链接的路径从头到尾没有拼接 hostname。这与文档描述完全一致跨域名的统计差异需要由使用方自己解决。文档也指出“this might be improved at some point in the future”未来可能改进但就当前版本而言官方给出了两个明确的处理选项。方案一为每个子域名创建独立的统计站点第一个选项是最直接、最彻底的隔离方案Create a new site for every domain; this is a completely separate site which has the same user, login, etc. You will need to use a different site for every (sub)domain.即为每一个域名分别创建一个独立站点。这些站点彼此完全隔离但共享同一个用户账号体系——你在同一套登录凭据下即可管理多个站点无需为每个站点注册不同的账号。从仓库结构来看这对应站点管理相关的实现站点创建/注册流程见 handlers/settings.go、handlers/user.go以及模板 tpl/serve_newsite.gohtml、tpl/signup.gohtml多站点列表与管理界面见 tpl/settings_sites.gohtml每个站点有独立的站点代码Site Code统计脚本的data-goatcounter属性指向各站独立的计数端点例如https://code-a.example.goatcounter.com/count与https://code-b.example.goatcounter.com/count。适用场景与取舍优点域名间数据天然隔离每个站点的指标访问量、来源、浏览器分布等互不干扰口径清晰代价需要在每个子域名页面分别放置指向对应站点的count.js与data-goatcounter端点且无法在同一个看板中看到跨域名的汇总数据。如果你只需要“各自统计、互不相干”这个方案就是最省心的选择。方案二将域名写入 path实现单站多域名聚合如果你希望所有域名/子域名的数据汇总到同一个看板官方给出的方案是把域名拼进 path而不是只发送裸路径If you want everything in a single overview then you can add the domain to the path, instead of just sending the path:script window.goatcounter { path: function(p) { return location.host p } } /script script async src//gc.zgo.at/count.js >页面 URL发送到 GoatCounter 的 pathhttps://a.example.com/patha.example.com/pathhttps://b.example.com/pathb.example.com/pathhttps://a.example.com/othera.example.com/other这样在同一个站点的看板中路径前缀如a.example.com、b.example.com就充当了域名维度的区分标记pages列表和来源统计里都能按域名前缀筛选或区分。文档还给出了针对子域名的优化建议For subdomains it it might be more useful to just add the first domain label instead of the full domain here, or perhaps just a short static string identifying the source.即如果只是区分子域名只取域名的第一级标签label通常更有用或者干脆拼接一个简短、固定的字符串来标识数据来源。例如把docs.example.com/path压成docs/path、blog.example.com/path压成blog/path比塞入完整域名更利于看板阅读与筛选script window.goatcounter { path: function(p) { // 只保留子域名的第一级标签如 docs.example.com - docs return location.hostname.split(.)[0] p } } /script源码级原理为什么这里必须使用回调函数方案二能生效的关键在于 public/count.js 中get_data()对path的取值逻辑window.goatcounter.get_data function(vars) { vars vars || {} var data { p: (vars.path undefined ? goatcounter.path : vars.path), // ... } var rcb, pcb, tcb // Save callbacks to apply later. if (typeof(data.r) function) rcb data.r if (typeof(data.t) function) tcb data.t if (typeof(data.p) function) pcb data.p if (is_empty(data.r)) data.r document.referrer if (is_empty(data.t)) data.t document.title if (is_empty(data.p)) data.p get_path() // ... if (pcb) data.p pcb(data.p) return data }执行顺序值得注意先取window.goatcounter.path的原始值如果它是一个函数则先保存为pcb并用默认值get_path()兜底最后调用回调data.p pcb(data.p)把默认 path 传入你的函数用返回值作为最终发送的 path。因此path: function(p) { return location.host p }中的p正是默认计算出的 path受 canonical 链接影响见下文回调返回null则该次浏览完全不被记录对应count.js中if (data.p null) return的判断。另外window.goatcounter的设置方式与加载时机也很重要。脚本开头执行window.goatcounter window.goatcounter || {}public/count.js因此你的自定义脚本必须放在count.js之前加载否则页面浏览可能已经发送完毕后来的赋值只会覆盖对象而不会生效。相关扩展canonical URL、端点切换与查询参数注入domains.md在结尾把读者引向“setting the endpoint in JavaScript”这一进阶话题详见 tpl/help/modify.md三者配合可以形成更完整的多域名处理工具箱。1. 按域名动态切换统计端点endpoint结合方案一的“每域名一站点”你可以在 JavaScript 中按当前 hostname 决定把数据发往哪个站点无需手改 HTMLscript var code ; switch (location.hostname) { case example.com: code a break case example.org: code b break default: code c } window.goatcounter { endpoint: https:// code .goatcounter.com/count, } /script script async src//gc.zgo.at/count.js/script注意两点官方文档原话data-goatcounter属性总是覆盖goatcounter.endpoint所以用了这种方式就别再写data-goatcounter且务必在count.js加载前设置或之后手动调用window.goatcounter.count()。2. canonical URL 对 path 的影响public/count.js 在计算默认 path 时会优先读取link relcanonical且仅当 canonical 的主机名去掉www.前缀后与当前页面主机一致时才采用它详细规则见 tpl/help/path.md。这与domains.md的讨论直接相关link relcanonical hrefhttps://example.com/path同一域名含www子域canonical 生效path 归一化到/path指向其他域名如https://my-other-site.com/pathGoatCounter 会忽略该值仍按当前页面 URL 计算 path——这既保护了多站点发布场景有些人跨站互指 canonical 利于 SEO但对统计是干扰也意味着跨域 canonical 不会帮你合并域名维度。3. 用get_query()注入查询参数/来源信息如果你在方案二的回调里还想保留页面查询参数可参考 public/count.js 提供的goatcounter.get_query(name)方法例如拼接?page参数script window.goatcounter { path: function() { return location.pathname ?page (goatcounter.get_query(page) || /) }, } /script这里同样必须用回调goatcounter对象此时尚未完全加载直接写对象字面量访问goatcounter.get_query会报未定义。更完整的path/referrer/title/event/no_session数据参数说明与count()/url()/filter()/bind_events()方法文档见 tpl/help/js.md。方案选择建议与注意事项先看需求再选方案需要按域名完全隔离的报表 → 方案一每域名一个独立站点每个子域名使用各自站点的统计端点需要跨域名汇总到同一看板 → 方案二域名注入 path用location.host p或精简的子域名标签前缀两者混合也可以例如生产站用方案二聚合测试站单独建站隔离。几点实践提醒方案二中 path 会被拼上域名看板里的“页面pages”列表、路径筛选paths.List、paths.PathFilter等查询见 db/query/都会包含该前缀筛选统计时要用包含域名的完整字符串方案二同一页面的 path 是location.host含端口号如果同一站点在 HTTP/HTTPS 与不同端口间切换前缀会不一致建议按需用location.hostname或只取一级标签来保证稳定若页面存在跨域 canonical 链接默认 path 会忽略它见上文自定义回调中可直接基于location对象计算不受影响上线后如果看不到数据先检查广告拦截器是否拦截了gc.zgo.at或你的计数域名参见 tpl/help/start.md。延伸阅读控制发送到 GoatCounter 的路径canonical URL、data-goatcounter-settings与window.goatcounter三种改 path 的方式JavaScript APIcount.js的全部设置项、数据参数与公开方法发送前修改数据自定义 path、referrer 及在 JS 中设置 endpoint 的更多示例接入与快速开始标准接入脚本、CSP 与广告拦截器排查源码参考public/count.js前端采集与 path 计算、hit.go命中数据模型、db/query/路径相关查询、tpl/settings_sites.gohtml站点管理界面。赞分享数据分析后端【免费下载链接】goatcounterEasy web analytics. No tracking of personal data.项目地址https://gitcode.com/gh_mirrors/go/goatcounter点击查看免费下载相关推荐domain-admin监控聚合多指标聚合分析domain admin监控聚合多指标聚合分析 概述监控聚合的价值与挑战 在现代分布式系统中域名和SSL证书的管理已成为企业运维的核心环节。随着业务规模的深入解析Nomulus顶级域名注册系统的架构设计与代码实现深入解析Nomulus顶级域名注册系统的架构设计与代码实现 引言为什么Nomulus架构值得研究 在互联网域名管理领域Nomulus作为Google COneUptime 域名监控Domain Monitor完全指南用 WHOIS/RDAP 守护域名注册与过期OneUptime 域名监控Domain Monitor完全指南用 WHOIS/RDAP 守护域名注册与过期 域名过期是比服务宕机更隐蔽的故障网站可以正可观测性后端运维前端云原生微服务AI Agent上一篇VidMuse生成质量优化解决常见问题的10个专业技巧下一篇KaMPKit项目在Xcode中调试Kotlin代码的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表