Nginx配置Google Analytics教程

网站配置 Google An­a­lyt­ics 的常见方式是在网站前端引用 an­a­lyt­ics.js 脚本,从前端利用 javascript 进行统计,这种方案的缺点是:

  • 客户端到 Google An­a­lyt­ics 之间的网络问题,包括 an­a­lyt­ics.js 脚本加载缓慢、向 Google An­a­lyt­ics 发送信息速度缓慢乃至失败等问题。
  • 客户端屏蔽 Google An­a­lyt­ics 的相关问题,包括常见的 ad­block 扩展等自带的屏蔽列表,利用 user­script 进行屏蔽等方式,这些客户端的手段都会导致统计的偏差问题。

如果将 Google An­a­lyt­ics 的统计工作从前端转移到后端完成,就可以有效避免上述问题,在阅读了相关参考资料后我发现直接使用 Nginx 自身的功能就可以完成这一工作,于是有了本文。

此方案的优点是:

  • 只需考虑服务器到 Google An­a­lyt­ics 的速度,不影响客户端的体验。
  • 统计数据真实准确,不受干扰与屏蔽。
  • 配置简单方便,使用 Ng­inx 自身的功能即可完成。

配置说明

Ng­inx 自带的 userid 模块可以用于标记各个用户,而 post_action 配置项可以在 Ng­inx 收到的请求处理完成后向某处发送一个异步的 Get 请求,这个请求会附带原始请求的 referer 与user-agent,利用这两个功能的这一个,我们可以配置 Ng­inx 在页面访问后发送相关信息到 Google An­a­lyt­ics 中,其具体配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
userid on;
userid_name cid;
userid_domain 你的域名;
userid_path /;
userid_expires max;

location @tracker {
internal;
proxy_method GET;
proxy_pass https://ssl.google-analytics.com/collect?v=1&tid=UA-XXXXXXXX-Y&$uid_set$uid_got&t=pageview&dh=$host&dp=$uri&uip=$remote_addr&dr=$http_referer&z=$msec;
proxy_set_header User-Agent $http_user_agent;
proxy_pass_request_headers off;
proxy_pass_request_body off;
}

location / {
try_files $uri $uri/ =404;
post_action @tracker;
}

userid模块将会在用户访问时检查 cook­ies 中是否有 cid 项,如果没有 cid 项,则会在返回的 header 中加入 set-cookies 头标记这个用户,并将 $uid_set 变量设定为 cid=XXXXXX 这一形式,将 $uid_got 变量设定为空。如果有 cid 项,则将 $uid_got 变量设定为 cid=XXXXXX 这一形式,将 $uid_set 变量设定为空。于是在 @tracker 部分,上述变量会将 $uid_set$uid_got 填充为cid=XXXXXX。
实际向 Google An­a­lyt­ics 提交数据时,tid为跟踪 ID,即类似 UA-123456-1 的用于区别是要向哪个 Google An­a­lyt­ics(分析)媒体资源发送数据的参数,可以从 Google An­a­lyt­ics 获得;cid即客户端 ID,以 cook­ies 的形式用于区分和追踪用户,这里通过 userid 模块完成;t、dh、dp参数用于标记事件类型,访问的网站与访问的路径;uip参数即用户的 IP 地址,用于追踪用户所处地区等信息;dr参数即用户的 ref­erer,用于追踪用户的来源信息;z参数没有实际意义,仅仅用于附加一个时间戳以防止向 Google An­a­lyt­ics 提交数据时,这个请求被缓存。

调试方法

如果希望提交更多数据,并对这一过程进行调试,最简单的方法是首先将配置文件中的 proxy_pass 部分网址从 https://ssl.google-analytics.com/ 修改为 http://127.0.0.1:9999 ,再在服务器上使用nc 监听服务器上的 9999 端口:

1
nc -k -l 0.0.0.0 9999

从本机访问该网站网站,就能从 nc 上看到本来将被提交到 Google An­a­lyt­ics 上的信息了,如:

1
2
3
4
GET /collect?v=1&tid=UA-XXXXXX-Y&cid=XXXXXX&t=pageview&dh=example.com&dp=/index.html&uip=123.123.123.123&dr=https://google.com&z=1448000000.000 HTTP/1.0
User-Agent: Mozilla/4.0
Host: 127.0.0.1:9999
Connection: close

随后通过 curl 向 Google An­a­lyt­ics 的调试服务器手动提交信息:

1
curl --user-agent "Mozilla/4.0" "https://www.google-analytics.com/debug/collect?v=1&tid=UA-XXXXXX-Y&cid=XXXXXX&t=pageview&dh=example.com&dp=/index.html&uip=123.123.123.123&dr=https://google.com&z=1448000000.000"

Google An­a­lyt­ics 的调试服务器会返回关于此次提交的详细信息,包括参数是否有错误、如何修正等,可以通过检查返回信息来确定配置是否正常,提交到此服务器上的数据并不会被记录到 Google An­a­lyt­ics 中。而 Google An­a­lyt­ics 的正常服务器只会返回 HTTP 状态码,难以进行调试。
手动提交上述信息后 Google An­a­lyt­ics 的返回如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"hitParsingResult": [ {
"valid": false,
"parserMessage": [ {
"messageType": "ERROR",
"description": "The value provided for parameter 'tid' is invalid. Please see http://goo.gl/a8d4RP#tid for details.",
"messageCode": "VALUE_INVALID",
"parameter": "tid"
} ],
"hit": "/debug/collect?v=1\u0026tid=UA-XXXXXX-Y\u0026cid=XXXXXX\u0026t=pageview\u0026dh=example.com\u0026dp=/index.html\u0026uip=123.123.123.123\u0026dr=https://google.com\u0026z=1448000000.000?_anon_uip=123.123.123.0"
} ],
"parserMessage": [ {
"messageType": "INFO",
"description": "Found 1 hit in the request."
} ]
}

明显可以看出此处的错误是 tid 参数错误,显然作为例子的 UA-XXXXXX-Y 并不是一个正确的 tid,更换成实际的tid 之后这个错误就被修复了。

DNT功能

用户可以启用 Do Not Track 功能向网站表明自己不希望被追踪,遵守该规则的网站就不会追踪用户的个人信息。
使用如下配置可以在只有用户未启用 DNT 功能时才向 Google An­a­lyt­ics 发送相关信息:

1
2
3
4
location / {
try_files $uri $uri/ =404;
if ($http_dnt != 1) {post_action @tracker;}
}

尽管如此,受 Ng­inx 程序本身的限制 userid 模块依旧会用 cook­ies 对用户进行标记,没有办法通过检测 DNT 头的方式来关闭它,但用户数据并不会被提交到 Google An­a­lyt­ics 上。