输入您的 GA4 Property ID(纯数字)
- Published on
- ...
- Authors

- Name
- Huashan
- @herohuashan
背景
作为一个托管在 Cloudflare Pages 上的 Hugo 静态博客,我一直想在文章页面显示真实的浏览量数据。但问题在于:
- Google Analytics 的 gtag.js 只能"写"数据,不能"读"历史数据
- 静态博客没有后端,无法直接调用 GA4 Data API
- 不想依赖第三方服务(如不蒜子),希望完全掌控数据
经过调研,我选择了 Cloudflare Workers + Google Analytics Data API 的方案,完美解决了这个问题。
最终效果
文章页面元信息中会显示浏览量(日期、阅读时间、作者后面):
2025-11-04 · 5 分钟 · geekhuashan · 👁 123 次浏览
特性:
- ✅ 显示 GA4 的真实全局浏览量
- ✅ 5 分钟双层缓存(Workers + 前端)
- ✅ 支持 1k+、10k+ 格式化
- ✅ 失败降级,不影响页面加载
- ✅ 完全免费(Cloudflare Workers 免费额度完全够用)
技术架构
访客浏览器
↓ 请求文章页面
前端 JavaScript (page-views.js)
↓ 1. 先显示缓存 (localStorage, 5 分钟)
↓ 2. 异步请求 API
Cloudflare Workers (pageviews.js)
↓ 1. 检查 Cache API (5 分钟)
↓ 2. 使用服务账号认证
↓ 3. 调用 GA4 Data API
Google Analytics 4
↓ 返回真实浏览量
前端显示:👁 123 次浏览
实现步骤
第 1 步:创建 Google Cloud 服务账号
1.1 启用 GA4 Data API
访问 Google Cloud Console,在 APIs & Services → Library 中搜索并启用:
Google Analytics Data API
1.2 创建服务账号
进入 IAM & Admin → Service Accounts,创建新服务账号:
- Service account name:
ga4-pageviews-reader - Role: 不需要 GCP 项目权限,跳过
下载 JSON 密钥文件(妥善保管,不要上传到 GitHub)。
1.3 在 GA4 中授权
登录 Google Analytics:
- 进入
Admin→Property access management - 点击
+ Add users - 输入服务账号邮箱(如
[email protected]) - 角色选择:Viewer(查看者)
- 取消勾选 "Notify new users by email"
1.4 获取 GA4 Property ID
在 GA4 管理页面,进入 Property settings,复制 Property ID(纯数字,如 123456789)。
第 2 步:创建 Cloudflare Workers
2.1 Workers 代码结构
创建 workers/pageviews.js:
export default {
async fetch(request, env) **
// 1. 处理 CORS
if (request.method === 'OPTIONS') **
return handleCORS(request);
**
// 2. 获取路径参数
const url = new URL(request.url);
const path = url.searchParams.get('path');
// 3. 检查缓存
const cached = await getCachedData(path, env);
if (cached) return jsonResponse(cached, 200, request, true);
// 4. 从 GA4 API 获取数据
const pageViews = await fetchGA4PageViews(path, env);
const data = **
path: path,
views: pageViews,
updatedAt: new Date().toISOString(),
cached: false
**;
// 5. 缓存并返回
await setCachedData(path, data, env);
return jsonResponse(data, 200, request);
**
};
核心功能:
- 使用 Google Cloud 服务账号认证(JWT + RS256 签名)
- 调用 GA4 Data API 查询指定页面的
screenPageViews - 使用 Cache API 缓存 5 分钟
- CORS 白名单保护
2.2 配置文件 wrangler.toml
name = "geekhuashan-pageviews"
main = "pageviews.js"
compatibility_date = "2024-01-01"
第 3 步:部署 Workers
3.1 安装 Wrangler CLI
npm install -g wrangler
3.2 登录 Cloudflare
cd workers
wrangler login
浏览器会自动打开授权页面,点击 Allow。
3.3 设置环境变量(Secrets)
设置 GA4 Property ID:
wrangler secret put GA4_PROPERTY_ID
设置 Google Cloud 凭证:
cat your-service-account.json | jq -c . | wrangler secret put GA4_CREDENTIALS
⚠️ 重要:Secrets 是加密存储在 Cloudflare 中的,不会泄露到 Git 仓库。
3.4 部署
wrangler deploy
成功后会显示 Workers URL:
✨ Deployed geekhuashan-pageviews
https://geekhuashan-pageviews.xxx.workers.dev
第 4 步:前端集成
4.1 HTML 结构(Hugo 模板)
修改 layouts/partials/post_meta.html,在元信息中添加浏览量占位符:
<span class="page-views" data-page-url="{{ .RelPermalink }}">
<span class="view-icon">👁</span>
<span class="view-count">0</span> 次浏览
</span>
4.2 JavaScript 调用 API
创建 assets/js/page-views.js:
(function() {
'use strict';
const API_ENDPOINT = 'https://your-worker.workers.dev';
const CACHE_DURATION = 5 * 60 * 1000; // 5 分钟
function initPageViews() {
const viewContainer = document.querySelector('.page-views');
if (!viewContainer) return;
const pageUrl = viewContainer.getAttribute('data-page-url');
const viewCountElement = viewContainer.querySelector('.view-count');
// 1. 先显示缓存
const cachedData = getCachedViewCount(pageUrl);
if (cachedData && cachedData.views !== undefined) **
viewCountElement.textContent = formatViewCount(cachedData.views);
**
// 2. 异步获取最新数据
fetchPageViews(pageUrl)
.then(function(data) {
if (data && data.views !== undefined) **
viewCountElement.textContent = formatViewCount(data.views);
setCachedViewCount(pageUrl, data);
**
})
.catch(function(error) {
console.warn('获取浏览量失败:', error);
if (!cachedData) **
viewCountElement.textContent = '-';
**
});
}
async function fetchPageViews(pageUrl) **
const url = `$**API_ENDPOINT**?path=$**encodeURIComponent(pageUrl)**`;
const response = await fetch(url);
if (!response.ok) throw new Error(`API 请求失败: $**response.status**`);
return await response.json();
**
function formatViewCount(count) **
if (count >= 10000) **
return Math.floor(count / 1000) + 'k+';
** else if (count >= 1000) **
return (count / 1000).toFixed(1).replace('.0', '') + 'k+';
** else **
return count.toString();
**
**
// 缓存函数省略...
// DOM 加载完成后初始化
if (document.readyState === 'loading') **
document.addEventListener('DOMContentLoaded', initPageViews);
** else **
initPageViews();
**
})();
4.3 CSS 样式
创建 assets/css/extended/page-views.css:
.page-views **
display: inline-flex;
align-items: center;
gap: 4px;
color: var(--secondary);
white-space: nowrap;
**
.page-views .view-icon **
font-size: 0.95em;
opacity: 0.8;
**
.page-views .view-count **
font-weight: 500;
color: var(--primary);
**
@media print **
.page-views **
display: none !important;
**
**
测试验证
本地测试
hugo server -D
open http://localhost:1313/your-article/
打开浏览器开发者工具(F12),查看:
- Network 标签页,找到
pageviews?path=请求 - 检查响应格式:
**
"path": "/your-article/",
"views": 123,
"updatedAt": "2025-11-04T07:22:54.892Z",
"cached": false
**
直接测试 Workers API
curl "https://your-worker.workers.dev?path=/test/"
性能优化
双层缓存策略
Workers Cache API(服务端):
- 缓存时长:5 分钟
- 作用:减少 GA4 API 调用次数
- 位置:Cloudflare 边缘节点
localStorage(客户端):
- 缓存时长:5 分钟
- 作用:减少 Workers API 请求
- 位置:访客浏览器
成本分析
Cloudflare Workers 免费计划:
- ✅ 100,000 请求/天
- ✅ 10ms CPU 时间/请求
- ✅ 无限制出站流量
实际消耗估算(假设日均 1000 PV):
- 1000 PV ÷ 5 分钟缓存 = 约 200 请求/天
- 远低于免费额度
Google Analytics Data API:
- ✅ 完全免费
- ✅ 无请求次数限制
总成本:$0 🎉
安全考虑
已实现的安全措施
- 服务账号最小权限:仅授予 GA4 查看者(Viewer)权限
- Secrets 加密存储:敏感信息通过
wrangler secret加密保存 - CORS 白名单:仅允许指定域名访问 API
- 速率限制:通过缓存机制防止滥用
敏感信息保护
⚠️ 绝对不要将以下内容提交到 Git:
- JSON 密钥文件(
*.json) - GA4 Property ID
- 服务账号邮箱
在 workers/.gitignore 中添加:
*.json
!package.json
!wrangler.toml
.env
*.key
可能遇到的问题
问题 1:API 返回 500 错误
原因:GA4 API 调用失败
排查步骤:
- 检查 GA4_PROPERTY_ID 是否正确(纯数字)
- 检查服务账号是否已在 GA4 中授权(Viewer 权限)
- 使用
wrangler tail查看实时日志
问题 2:CORS 错误
原因:Workers 中的 CORS 白名单未包含您的域名
解决:修改 pageviews.js 中的 ALLOWED_ORIGINS:
const ALLOWED_ORIGINS = [
'https://geekhuashan.com',
'http://localhost:1313'
];
重新部署:wrangler deploy
问题 3:浏览量显示为 0
原因:GA4 中该页面路径无数据
排查:
- 登录 Google Analytics,检查路径格式是否正确
- GA4 数据有 24-48 小时延迟,新文章可能暂时无数据
- 确认 gtag.js 是否正确加载并发送
page_view事件
扩展优化
1. 绑定自定义域名
在 Cloudflare Dashboard 配置 Workers Route:
- Route:
api.geekhuashan.com/pageviews* - Worker:
geekhuashan-pageviews
更新前端 API 端点:
const API_ENDPOINT = 'https://api.geekhuashan.com/pageviews';
2. 显示其他指标
修改 Workers 中的 GA4 API 查询,可以获取:
- 访客数(
activeUsers) - 停留时间(
averageSessionDuration) - 跳出率(
bounceRate)
3. 使用 KV 存储
将 Cache API 升级为 Cloudflare KV,获得更稳定的缓存:
# wrangler.toml
[kv_namespaces](/kv_namespaces)
binding = "PAGEVIEWS_KV"
id = "your-kv-namespace-id"
总结
通过 Cloudflare Workers + Google Analytics Data API 的方案,我成功为静态博客添加了真实的浏览量统计功能,核心优势:
✅ 完全免费:Cloudflare 和 GA4 的免费额度完全够用 ✅ 性能优秀:双层缓存 + 边缘计算,全球低延迟 ✅ 数据准确:直接从 GA4 获取真实数据 ✅ 完全掌控:不依赖第三方服务,代码和数据都在自己手中 ✅ 易于维护:Serverless 架构,无需管理服务器
如果您也在使用 Hugo + Cloudflare Pages,强烈推荐尝试这个方案!
参考资源
项目源码
完整代码已开源在 GitHub(敏感信息已移除):
# 文件结构
workers/
├── pageviews.js # Workers 主函数
├── wrangler.toml # 部署配置
└── package.json # npm 依赖
themes/your-theme/
├── assets/
│ ├── js/page-views.js # 前端脚本
│ └── css/extended/page-views.css # 样式
└── layouts/partials/
├── post_meta.html # 显示位置
└── extend_footer.html # 脚本加载
欢迎 Star 和 Fork!⭐
2024-11-04 更新:文章首发,欢迎交流讨论!