DarkNode

Life, the Universe and Everything

Ng­inx 内配置 Google An­a­lyt­ics 指南

本文发表于:
最后修改于:
分类:network
合计信息量:7.02kb

相关说明

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

  1. 客户端到 Google An­a­lyt­ics 之间的网络问题,包括 an­a­lyt­ics.js 脚本加载缓慢、向 Google An­a­lyt­ics 发送信息速度缓慢乃至失败等问题。由于各地网络情况不一,唯一通用的解决方案需要自己反向代理一个 an­a­lyt­ics.js 脚本,并且由服务器中转向 Google An­a­lyt­ics 发送信息的通讯。
  2. 客户端屏蔽 Google An­a­lyt­ics 的相关问题,包括常见的 ad­block 扩展等自带的屏蔽列表,利用 user­script 进行屏蔽等方式,这些客户端的手段都会导致统计的偏差问题。

如果将 Google An­a­lyt­ics 的统计工作从前端转移到后端完成,就可以有效避免上述问题,比如使用 an­a­lyt­icsd 处理 Ng­inx 的日志,并将各类事件上传至 Google An­a­lyt­ics 上,或者使用 uni­ver­sal-an­a­lyt­ics 将 Google An­a­lyt­ics 集成到 Nodejs 应用中。

上述的两个 Nodejs 程序都是基于 Mea­sure­ment Pro­to­col 开发的,在阅读了相关参考资料后我发现直接使用 Ng­inx 自身的功能就可以完成这一工作,于是有了本文。

此方案的优点是:

  1. 只需考虑服务器到 Google An­a­lyt­ics 的速度,不影响客户端的体验。
  2. 统计数据真实准确,不受干扰与屏蔽。
  3. 用户使用的语言可以通过浏览器发送的 Ac­cept-Lan­guage 获得用户设定的 Pre­ferred lan­guage,而 js 脚本只能获得浏览器安装时选择的语言,这是一个 Bug/Fea­ture
  4. 配置简单方便,不需要额外安装 Nodejs 等程序和包管理器,使用 Ng­inx 自身的功能即可完成。

配置说明

服务器信息:

Ng­inx 信息:

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

http {
    map $http_ac­cept_lan­guage $lang { 
        ~^([a-zA-Z-]*) $1;
    }

    server {
        userid on;
        userid_name cid;
        userid_do­main 你的域名;
        userid_path /;
        userid_ex­pires max;
        
        lo­ca­tion @tracker {
            in­ter­nal;
            proxy_method GET;
            proxy_pass https://ssl.google-an­a­lyt­ics.com/col­lect?v=1&tid=UA-XXXXXXXX-Y&$uid_set$uid_got&t=pageview&dh=$host&dp=$uri&uip=$re­mote_addr&dr=$http_ref­erer&ul=$lang&z=$msec;
            proxy_set_header User-Agent $http_user_agent;
            proxy_pass_re­quest_head­ers off;
            proxy_pass_re­quest_body off;
        }
        
        lo­ca­tion / {
            try_files $uri $uri/ =404;
            post_ac­tion @tracker;
        }
    }

}

userid 模块将会在用户访问时检查 cook­ies 中是否有 cid 项,如果没有 cid 项,则会在返回的 header 中加入 set-cook­ies 头标记这个用户,并将$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 提交数据时:

注意事项

在配置监听 IPv6 和 IPv4 时,有两种配置方式:

lis­ten [::]:80 ipv6only=off;

lis­ten 80;
lis­ten [::]:80 ipv6only=on;

如果使用前者,那么 re­mote_addr 变量将会被表示为 IPv4-mapped IPv6 ad­dresses 即::ffff:123.123.123.123 这样的形式,如果使用后者,那么 re­mote_addr 变量将会被表示为 123.123.123.123 这样的正常的形式。

Google An­a­lyt­ics 对 IP 会进行匿名化处理,将::ffff:123.123.123.123 处理为::,而将 123.123.123.123 处理为 123.123.123.0,显然前者会导致地区识别错误等一系列问题,所以请务必使用后者以确保 Google An­a­lyt­ics 正确处理提交的数据。

调试方法

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

$ nc -k -l 0.0.0.0 9999

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

GET /col­lect?v=1&tid=UA-XXXXXX-Y&cid=XXXXXX&t=pageview&dh=ex­am­ple.com&dp=/in­dex.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
Con­nec­tion: close

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

$ curl --user-agent "Mozilla/4.0" "https://www.google-an­a­lyt­ics.com/de­bug/col­lect?v=1&tid=UA-XXXXXX-Y&cid=XXXXXX&t=pageview&dh=ex­am­ple.com&dp=/in­dex.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 的返回如下:

{
  "hit­Pars­in­gRe­sult": [ {
    "valid": false,
    "parser­Mes­sage": [ {
      "mes­sageType": "ER­ROR",
      "de­scrip­tion": "The value pro­vided for pa­ra­me­ter 'tid' is in­valid. Please see http://goo.gl/a8d4RP#tid for de­tails.",
      "mes­sage­Code": "VALUE_IN­VALID",
      "pa­ra­me­ter": "tid"
    } ],
    "hit": "/de­bug/col­lect?v=1\u0026tid=UA-XXXXXX-Y\u0026cid=XXXXXX\u0026t=pageview\u0026dh=ex­am­ple.com\u0026dp=/in­dex.html\u0026uip=123.123.123.123\u0026dr=https://google.com\u0026z=1448000000.000?_anon_uip=123.123.123.0"
  } ],
  "parser­Mes­sage": [ {
    "mes­sageType": "INFO",
    "de­scrip­tion": "Found 1 hit in the re­quest."
  } ]
}

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

DNT 功能

用户可以启用 Do Not Track 功能向网站表明自己不希望被追踪,遵守该规则的网站就不会追踪用户的个人信息。

使用如下配置可以在只有用户未启用 DNT 功能时才向 Google An­a­lyt­ics 发送相关信息:

lo­ca­tion / {
    try_files $uri $uri/ =404;
    if ($http_dnt != 1) {
        post_ac­tion @tracker;
    }
}

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