因为Google Analytics,我的PageSpeed Insights得分为99/100 - 我应该如何缓存GA?

260
我正在追求100/100的PageSpeed得分,差不多达到目标了。我正在努力寻找一个好的解决方案来缓存Google Analytics。
以下是我收到的消息:
利用浏览器缓存 为静态资源设置到期日期或最大年龄的HTTP标头,指示浏览器从本地磁盘加载先前下载的资源,而不是通过网络获取。 利用以下可缓存资源的浏览器缓存: http://www.google-analytics.com/analytics.js(2 小时)
我找到的唯一解决方案是 2012 年的,我认为这不是一个好的解决方案。基本上,您需要复制 GA 代码并将其托管在自己的服务器上。然后,每天运行一个 Cron 作业,重新检查 Google,以获取最新的 GA 代码并替换它。

http://diywpblog.com/leverage-browser-cache-optimize-google-analytics/

还有什么其他方法可以在使用Google Analytics的同时达到100/100?

谢谢。


1
我使用了cron方法,没有使用cron(在加载和缓存onload时)。如果您需要,我可以分享PHP代码。我已经解决了GA修复建议的问题。但是还有一个小问题:我留下了“Cache-Control: max-age=604800”头部,这比5分钟缓存时间要长得多。 - Roman Losev
6
但这真的是一个好主意吗?在您的服务器上缓存此文件意味着浏览器将不得不重新下载它,而不是重复使用已经通过访问其他使用Google Analytics的网站缓存的文件。因此,这实际上可能会稍微减慢您的访问者速度。 - s427
可能是Leverage browser caching for 3rd party JS的重复问题。 - Joe
20个回答

259

好的,如果Google欺骗了你,你可以回击Google:

这是PageSpeed的用户代理:

“Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.8 (KHTML, like Gecko; Google Page Speed Insights) Chrome/19.0.1084.36 Safari/536.8”

您可以插入条件语句,以避免向PageSpeed提供分析脚本:

<?php if (!isset($_SERVER['HTTP_USER_AGENT']) || stripos($_SERVER['HTTP_USER_AGENT'], 'Speed Insights') === false): ?>
// your analytics code here
<?php endif; ?>

显然,这并不会带来任何真正的改善,但如果你唯一关心的是获得100/100的分数,这个方法可以做到。


4
聪明......可惜我使用边缘缓存,因为这个脚本只有在每个请求都到达您的源站时才能工作 :( - Amy Neville
54
使用JS加载它 :) if(navigator.userAgent.indexOf("Speed Insights") == -1) { /* 在此处添加分析代码 */ } - Rob W
2
恕我直言,那是作弊!你可以把这个规则应用到很多其他事情上,比如通过不加载内容来提高速度。迟早有一天,谷歌可能会开始通过比较不同用户代理的HTML来惩罚使用此规则的网站。 - João Pimentel Ferreira
12
警告:此方法已不再起作用。由Lighthouse支持的Page Speed Insights使用默认的userAgent,无法被检测到。 - David Vielhuber
1
@DavidVielhuber,除了这个解决方案,还有其他好的解决方案吗? - labago
显示剩余19条评论

42

Google Analytics js库的一个子集被称为ga-lite,你可以以任何方式缓存它。

该库使用Google Analytics的公共REST API将用户跟踪数据发送到Google。您可以从关于ga-lite的博客文章中了解更多信息。

免责声明:我是这个库的作者。我曾经遇到过这个具体问题,而我找到的最佳解决方案是实现这个解决方案。


23

这是一个非常简单的使用JS进行基本GA跟踪的解决方案,也适用于边缘缓存/代理(这是从一条评论转换而来的):

if(navigator.userAgent.indexOf("Speed Insights") == -1) {
  (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','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-XXXXXXXXX-X', 'auto');
  ga('send', 'pageview');
}

注意:这是默认的 GA 脚本。您可能有其他 ga() 调用,如果有的话,在调用 ga() 之前始终需要检查用户代理,否则可能会出现错误。


2
针对“注:”部分,您可以在代码片段之前声明ga = function(){};,这样执行ga();时就会静默失败,因此您不必在代码中的每个位置都检查该函数是否存在。 - István Pálinkás
2
如何在脚本中添加此内容:<script async src="https://www.googletagmanager.com/gtag/js?id=UA-xx6600xx-1"></script> - Navnish Bhardwaj
1
注意:这可能已经不再适用。速度得分确实会对搜索信号产生影响(请参见https://developers.google.com/search/docs/guides/page-experience),但具体程度尚不清楚。 - Rob W

16

我觉得你不用太担心这个问题。听起来这是谷歌的问题,不要把文件放在你自己的服务器上,因为那样会带来很多新的问题。

他们可能需要每次调用该文件而不是从客户端缓存中获取文件,因为这样才能准确统计访问量。

如果你对此感到不满意,可以在谷歌洞察本身上运行谷歌洞察URL, 逗一下自己,放松心情,然后继续工作。


68
他想知道如何达到100,而不是问是否99就可以了。 - Erick Engelhardt
4
这个答案不正确,Analytics.js 文件下载的来源并不影响分析跟踪。自行托管分析文件的问题在于你必须手动更新到最新版本(每年几次)。 - Matthew Dolman
1
感谢Matthew指出这一点。显然我错了,这是好事,但我仍然认为在自己的服务器上托管此文件不是一个好主意,因为我可以想象它会带来很多新问题。OP的问题是如何达到100页速度,我的答案是不要担心达到那个100。这可能是一个非常烦人的答案,但这就是我。 - Leo Muller
3
对于那些认为99分不够的人来说,一个好的回答是:最好把时间投入到解决真正的问题上。请专注于重要的事情。 - linqu
@ErickEngelhardt 您是正确的,但是如果人们问一个问题,您认为他们的目标不是最佳的,那么您应该提醒他们哪个解决方案可能更适合他们。 - observer

10
在谷歌文档中,他们已经确定了一个pagespeed过滤器,可以异步加载脚本:

在谷歌文档中,他们已经确定了一个pagespeed过滤器,可以异步加载脚本:

ModPagespeedEnableFilters make_google_analytics_async

您可以在这里找到文档:https://developers.google.com/speed/pagespeed/module/filter-make-google-analytics-async

需要强调的一点是,该过滤器被认为是高风险的。从文档中可以看出:

make_google_analytics_async 过滤器是实验性的,并没有经过广泛的实际测试。如果过滤器错过了返回值的 Google Analytics 方法调用,则会导致重写引起错误。如果发现此类方法,则会跳过重写。然而,如果它们出现在加载之前、在 "onclick" 等属性中或在外部资源中,则将错过不合格的方法。这些情况预计很少出现。


7

将analytics.js存储在本地,但谷歌不建议这样做:https://support.google.com/analytics/answer/1032389?hl=en

这么做不被推荐是因为谷歌可以随时更新脚本,所以每周下载分析JavaScript的脚本就好了,您就不会有麻烦!

顺便说一下,这个解决方案可以防止广告拦截器拦截谷歌分析脚本


它并不完全绕过Adblock(仍会阻止ajax调用),但至少您可以获得会话和页面视图。 - NiloVelez

7

2
请注意,谷歌明确不支持此操作:https://support.google.com/analytics/answer/1032389?hl=en - steel

7

Varvy.com100/100 Google页面速度洞察)仅在用户滚动页面时加载Google分析代码:

var fired = false;

window.addEventListener("scroll", function(){
    if ((document.documentElement.scrollTop != 0 && fired === false) || (document.body.scrollTop != 0 && fired === false)) {

        (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-XXXXXXXX-X', 'auto');
        ga('send', 'pageview');

        fired = true;
    }
}, true);

9
如果访问者不滚动页面而只是点击链接,他将不会被算入分析数据。 - Ross
@RossIvantsiv 你也可以处理点击事件! - ar099968
我不建议使用这个解决方案。因为有些触摸设备最初不会执行事件,所以你永远无法确保所有数据都被跟踪。以购买跟踪为例,当你从第三方窗口返回时,如果没有加载GTM或分析标签,则购买将永远无法被跟踪。以上仅是我的想法。 - Lervad

6
你可以通过自己的服务器代理 Google Analytics 脚本,将其保存在本地并每小时自动更新该文件,以确保始终使用来自Google的最新版本。我已经在几个网站上实现了这一点,一切运作良好。以下是我在MEAN堆栈中实现Google Analytics代理路由的方法。在我的博客上应用。
router.get('/analytics.js', function (req, res, next) {
    var fileUrl = 'http://www.google-analytics.com/analytics.js';
    var filePath = path.resolve('/content/analytics.js');

    // ensure file exists and is less than 1 hour old
    fs.stat(filePath, function (err, stats) {
        if (err) {
            // file doesn't exist so download and create it
            updateFileAndReturn();
        } else {
            // file exists so ensure it's not stale
            if (moment().diff(stats.mtime, 'minutes') > 60) {
                updateFileAndReturn();
            } else {
                returnFile();
            }
        }
    });

    // update file from remote url then send to client
    function updateFileAndReturn() {
        request(fileUrl, function (error, response, body) {
            fs.writeFileSync(filePath, body);
            returnFile();
        });
    }

    // send file to client
    function returnFile() {
        res.set('Cache-Control', 'public, max-age=' + oneWeekSeconds);
        res.sendFile(filePath);
    }
});

ASP.NET MVC中的Google Analytics代理操作方法

这是我在其他使用ASP.NET MVC构建的网站上实现它的方式。

public class ProxyController : BaseController
{
    [Compress]
    public ActionResult GoogleAnalytics()
    {
        var fileUrl = "https://ssl.google-analytics.com/ga.js";
        var filePath = Server.MapPath("~/scripts/analytics.js");

        // ensure file exists 
        if (!System.IO.File.Exists(filePath))
            UpdateFile(fileUrl, filePath);

        // ensure file is less than 1 hour old
        var lastModified = System.IO.File.GetLastWriteTime(filePath);
        if((DateTime.Now - lastModified).TotalMinutes > 60)
            UpdateFile(fileUrl, filePath);

        // enable caching for 1 week for page speed score
        Response.AddHeader("Cache-Control", "max-age=604800");

        return JavaScript(System.IO.File.ReadAllText(filePath));
    }

    private void UpdateFile(string fileUrl, string filePath)
    {
        using (var response = WebRequest.Create(fileUrl).GetResponse())
        using (var dataStream = response.GetResponseStream())
        using (var reader = new StreamReader(dataStream))
        {
            var body = reader.ReadToEnd();
            System.IO.File.WriteAllText(filePath, body);
        }
    }
}

这是MVC ProxyController使用的CompressAttribute,用于Gzip压缩。
public class CompressAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {

        var encodingsAccepted = filterContext.HttpContext.Request.Headers["Accept-Encoding"];
        if (string.IsNullOrEmpty(encodingsAccepted)) return;

        encodingsAccepted = encodingsAccepted.ToLowerInvariant();
        var response = filterContext.HttpContext.Response;

        if (encodingsAccepted.Contains("gzip"))
        {
            response.AppendHeader("Content-encoding", "gzip");
            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
        }
        else if (encodingsAccepted.Contains("deflate"))
        {
            response.AppendHeader("Content-encoding", "deflate");
            response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
        }
    }
}

更新的Google Analytics脚本

在客户端,我将分析路径附加上当前日期,直到小时,这样浏览器就不会使用超过一小时的缓存版本。

<!-- analytics -->
<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', '/analytics.js?d=' + new Date().toISOString().slice(0, 13), 'ga');
</script>

5

我已经做了这个,但是“https://yoursite.com/analytics.js”返回404错误(当然我已经替换成了自己的网站)。 - Astro-Otter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接