使用Cloudflare Workers執行Google Analytics
原因:
我一直以来都在使用Google Analytics统计自己的博客和几个网站访问情况。但是一个gzip以后都还有
45KB
大小的analytics.js
、Cache-Control
还只有7200秒;Google国内的数据中心会被抽风不说,www.google-analytics.com
域名早就上了各个广告屏蔽软件的黑名单。
說明:
- 該方案所收集的數據有限,如需更詳細數據請用Google Analytics提供的程式碼。
- Cloudflare Workers免費方案額度為一天/10萬個請求,對於流量很小的個人網站是綽綽有餘。大流量網站不適用──且收集的數據需要很詳細吧。
參照其方法,到Cloudflare新建一個Workers,在Script頁面將work.js內容複製貼上(因為是即時頁面讀取較慢,瀏覽器會一直提示停止執行):
//const AllowedReferrer = 'skk.moe'; // ['skk.moe', 'suka.js.org'] multiple domains is supported in array format
addEventListener('fetch', (event) => {
event.respondWith(response(event));
});
async function senData(event, url, uuid, user_agent, page_url) {
const encode = (data) => encodeURIComponent(decodeURIComponent(data));
const getReqHeader = (key) => event.request.headers.get(key);
const getQueryString = (name) => {
const pattern = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
const r = url.search.substr(1).match(pattern);
return (r !== null) ? unescape(r[2]) : null;
};
const reqParameter = {
headers: {
'Host': 'www.google-analytics.com',
'User-Agent': user_agent,
'Accept': getReqHeader('Accept'),
'Accept-Language': getReqHeader('Accept-Language'),
'Accept-Encoding': getReqHeader('Accept-Encoding'),
'Cache-Control': 'max-age=0'
}
};
const pvData = `tid=${encode(getQueryString('ga'))}&cid=${uuid}&dl=${encode(page_url)}&uip=${getReqHeader('CF-Connecting-IP')}&ua=${user_agent}&dt=${encode(getQueryString('dt'))}&de=${encode(getQueryString('de'))}&dr=${encode(getQueryString('dr'))}&ul=${getQueryString('ul')}&sd=${getQueryString('sd')}&sr=${getQueryString('sr')}&vp=${getQueryString('vp')}`;
const perfData = `plt=${getQueryString('plt')}&dns=${getQueryString('dns')}&pdt=${getQueryString('pdt')}&rrt=${getQueryString('rrt')}&tcp=${getQueryString('tcp')}&srt=${getQueryString('srt')}&dit=${getQueryString('dit')}&clt=${getQueryString('clt')}`
const pvUrl = `https://www.google-analytics.com/collect?v=1&t=pageview&${pvData}&z=${getQueryString('z')}`;
const perfUrl = `https://www.google-analytics.com/collect?v=1&t=timing&${pvData}&${perfData}&z=${getQueryString('z')}`
await fetch(pvUrl, reqParameter);
await fetch(perfUrl, reqParameter);
}
async function response(event) {
const url = new URL(event.request.url);
const getReqHeader = (key) => event.request.headers.get(key);
const Referer = getReqHeader('Referer');
const user_agent = getReqHeader('User-Agent');
const ref_host = (() => {
try {
return new URL(Referer).hostname;
} catch (e) {
return ""
}
})();
let needBlock = false;
needBlock = (!ref_host || ref_host === '' || !user_agent || !url.search.includes('ga=UA-')) ? true : false;
if (typeof AllowedReferrer !== 'undefined' && AllowedReferrer !== null && AllowedReferrer) {
let _AllowedReferrer = AllowedReferrer;
if (!Array.isArray(AllowedReferrer)) _AllowedReferrer = [_AllowedReferrer];
const rAllowedReferrer = new RegExp(_AllowedReferrer.join('|'), 'g');
needBlock = (!rAllowedReferrer.test(ref_host)) ? true : false;
console.log(_AllowedReferrer, rAllowedReferrer, ref_host);
}
if (needBlock) {
return new Response('403 Forbidden', {
headers: { 'Content-Type': 'text/html' },
status: 403,
statusText: 'Forbidden'
});
}
const getCookie = (name) => {
const pattern = new RegExp('(^| )' + name + '=([^;]*)(;|$)');
const r = (getReqHeader('cookie') || '').match(pattern);
return (r !== null) ? unescape(r[2]) : null;
};
const createUuid = () => {
let s = [];
const hexDigits = '0123456789abcdef';
for (let i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = '-';
return s.join('');
};
const _uuid = getCookie('uuid');
const uuid = (_uuid) ? _uuid : createUuid();
// To sent data to google analytics after response id finished
event.waitUntil(senData(event, url, uuid, user_agent, Referer));
// Return an 204 to speed up: No need to download a gif
let response = new Response(null, {
status: 204,
statusText: 'No Content'
});
if (!_uuid) response.headers.set('Set-Cookie', `uuid=${uuid}; Expires=${new Date((new Date().getTime() + 365 * 86400 * 30 * 1000)).toGMTString()}; Path='/';`);
return response
}
修改網站<head>
位置,將Google Analytics程式碼換成:
<script>
window.ga_tid = "UA-XXXXX-Y"; // {String} The trackerID of your site.
window.ga_api = "https://example.com/xxx/"; // {String} The route of your cloudflare workers you just registered before.
</script>
<script src="https://cdn.jsdelivr.net/npm/cfga@1.0.1" async></script>
"UA-XXXXX-Y"
:Google Analytics的追蹤ID。"https://example.com/xxx/"
:Cloudflare Workers新建好的網址,例如https://xxx-xxx-xxx.yourname.workers.dev/
。
以上步驟完成後,到Google Analytics網站的即時頁面檢查是否有變化。
參考網站: