我如何动态地设置谷歌通用分析的跟踪代码,同时坚持不允许内联脚本的CSP



我有一个网站的解决方案,得到部署到几个不同的url,每个都是品牌为不同的客户端。部署过程在web中设置各种特定于客户端的配置数据。配置、数据库等。相同的网站代码用于所有客户端,但不同的配置数据意味着网站的外观和行为对每个客户端都不同。

我想在每个客户端基础上设置的一件事是Google通用分析跟踪代码。这是出现在被添加到每个页面的脚本块中的代码(在下面的示例中'UA-12345678-1'):

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
  ga('create', 'UA-12345678-1', 'auto');
  ga('send', 'pageview');
</script> 

我在ViewBag中有跟踪代码,所以如果我准备把这个脚本块直接放在我的HTML页面中(或在我的主布局中),那么插入跟踪代码将是非常容易的:

ga('create', '@ViewBag.GoogleTrackingCode', 'auto');

然而,我正在使用内容安全策略(CSP)功能来锁定网站,并且作为其中的一部分,我已经禁用了内联脚本:所有脚本必须从.js文件加载。

因此,我创建了一个JavaScript文件,其中包含上面脚本块的修改版本,我从HTML页面引用它:
(function (i, s, o, g, r, a, m) {
    i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
          (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
          m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', ga_token, 'auto');
ga('send', 'pageview');

我的计划是在这段脚本运行之前设置ga_token变量的值。我想我应该把变量值隐藏在HTML的某个地方(在data-*属性中):

<div id="ga-token-data" data-ga-token="@ViewBag.GoogleAnalyticsToken">

…并使用一些JavaScript(当然是在。js文件中)获取该值:

$(document).ready(function () {
    ga_token = $("#ga-token-data").data("ga-token");
})

然而,由于执行的顺序,这被证明是棘手的。根据谷歌的文档,脚本块应该放在HTML页面关闭<head>标签之前,虽然有一些花哨的东西在进行,所以它不试图做任何事情,直到页面加载,ga('create', ...调用跟踪代码实际上立即执行。因此,ga_token的值在使用之前没有设置。

理论上,我可以将设置ga_token值的代码移动到Google脚本块的上方,但是这样做的话,我将在加载DOM之前执行该代码-在这种情况下,我可能无法获取我需要的值。(我当然不能使用jQuery,因为我不加载jQuery库,直到后来)。

还有别的方法吗?

在完全加载之前读取DOM是可以的,操作节点是有风险的。所以你的解决方案可以像这样:

生成的HTML页面

<form id="serverData">
    <input type="hidden" name="gaToken" value="@ViewBag.GoogleAnalyticsToken" />
</form>

修改后的分析加载器

<script>
var ga_token = document.getElementById("serverData").gaToken.value;
(function (i, s, o, g, r, a, m) {
    i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
          (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
          m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', ga_token, 'auto');
ga('send', 'pageview');
</script>

另一个没有jQuery和<form>的实现…

<html id="dashboard" data-ga_id="{{ settings.GOOGLE_ANALYTICS_ACCOUNT }}">

然后…

var ga_id = document.getElementById("push-dashboard").dataset.ga_id;
if (ga_id) {
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js,'ga');
    ga('create', ga_id, 'auto');
    ga('send', 'pageview');
}

最新更新