PageSpeed Insights 99/100 因为 Google Analytics - 如何缓存 GA?

PageSpeed Insights 99/100 because of Google Analytics - How can I cache GA?

我正在寻求在 PageSpeed 上达到 100/100,我快到了。我正在尝试找到一个好的解决方案来缓存 Google Analytics。

这是我收到的消息:

利用浏览器缓存 在 HTTP headers 中为静态资源设置到期日期或最长期限会指示浏览器从本地磁盘而不是通过网络加载以前下载的资源。 利用浏览器缓存以下可缓存资源: 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?

谢谢。

您可以尝试在本地托管 analytics.js 并使用缓存脚本或手动更新其内容。

js 文件每年只更新几次,如果您不需要任何新的跟踪功能,请手动更新它。

https://developers.google.com/analytics/devguides/collection/analyticsjs/changelog

Google cautions 反对使用分析脚本的本地副本。 但是,如果您这样做,您可能希望使用插件和调试脚本的本地副本。

第二个 concern 具有积极缓存的是您将从缓存的页面中获得点击量 - 这些页面可能已更改或已从站点中删除。

本地存储 analytics.js,但 google 不推荐: https://support.google.com/analytics/answer/1032389?hl=en

不推荐,因为 google 可以在需要时更新脚本,所以只需每周执行一个下载分析 javascript 的脚本,您就不会遇到麻烦!

顺便说一下,此解决方案可防止 adblock 阻止 google 分析脚本

我不会担心的。不要把它放在你自己的服务器上,这听起来像是 Google 的问题,但它已经很好了。将文件放在自己的服务器上会产生很多新问题。

他们可能需要每次都调用该文件而不是从客户端的缓存中获取它,因为那样您就不会计算访问次数。

如果您对此感到满意,运行 Google 见解 URL 关于 Google 见解本身,笑一笑,放松一下,继续前进与你的工作。

您可以缩小页面中的所有脚本,包括 analytics.js 使用:

记得在使用前缩小文件。否则会消耗更多的处理时间。

要解决此问题,您必须在本地下载文件并 运行 一个 cron 作业以保持更新。注意:这根本不会使您的网站更快,因此最好忽略它。

但是,出于演示目的,请遵循本指南: http://diywpblog.com/leverage-browser-cache-optimize-google-analytics/

有一个名为 ga-lite 的 Google Analytics js 库的子集,您可以根据需要缓存它。

图书馆使用 Google Analytics' public REST API 将用户跟踪数据发送到 Google。您可以从 the blog post about ga-lite.

阅读更多内容

免责声明:我是这个库的作者。我为解决这个具体问题而苦苦挣扎,我发现最好的结果是实施了这个解决方案。

在 Google 文档中,他们确定了一个 pagespeed 过滤器,它将异步加载脚本:

ModPagespeedEnableFilters make_google_analytics_async

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

要强调的一件事是过滤器被认为是高风险的。来自文档:

The make_google_analytics_async filter is experimental and has not had extensive real-world testing. One case where a rewrite would cause errors is if the filter misses calls to Google Analytics methods that return values. If such methods are found, the rewrite is skipped. However, the disqualifying methods will be missed if they come before the load, are in attributes such as "onclick", or if they are in external resources. Those cases are expected to be rare.

好吧,如果 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 的分数,那么它就可以了。

您可以通过自己的服务器代理 google 分析脚本,将其保存在本地并每小时自动更新文件以确保它始终是 google 的最新版本。

我现在已经在几个站点上完成了此操作,一切正常。

Google NodeJS/MEAN 堆栈中的分析代理路由

这就是我在使用 MEAN 堆栈构建的 my blog 上实现它的方式。

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);
    }
});

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

这就是我在使用 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 用于 Gzip 压缩的 CompressAttribute

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 -->
<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>

varvy.com (100/100 Google page speed insight) 仅当用户滚动页面时才加载 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);

尝试在

之前插入
<script async='async' src='https://cdn.jsdelivr.net/ga-lite/latest/ga-lite.min.js'></script> <script>var galite=galite||{};galite.UA="xx-xxxxxxx-x";</script>

请将 xx-xxxxxxx-x 更改为您的代码,请在此处查看实现 http://www.gee.web.id/2016/11/how-to-leverage-browser-caching-for-google-analitycs.html

这是一个使用 JS 的非常简单的解决方案,用于基本的 GA 跟踪,它也适用于边缘 caches/proxies(这是从评论转换而来):

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() 之前始终检查用户代理,否则可能会出错。

这可能会奏效 :)

<script>
  $.ajax({
  type: "GET",
  url: "https://www.google-analytics.com/analytics.js",
  success: function(){},
  dataType: "script",
  cache: true
  });
</script>

对于 Nginx:

location ~ /analytics.js {
        proxy_pass https://www.google-analytics.com;
        expires 31536000s;
        proxy_set_header Pragma "public";
        proxy_set_header Cache-Control "max-age=31536000, public";
    }

然后改变路径https://www.google-analytics.com/analytics.js to https://yoursite.com/analytics.js

PHP

将此添加到您的 HTML 或 PHP 代码中:

<?php if (!isset($_SERVER['HTTP_USER_AGENT']) || stripos($_SERVER['HTTP_USER_AGENT'], 'Speed Insights') === false): ?>
  <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','https://www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-PUT YOUR GOOGLE ANALYTICS ID HERE', 'auto');
    ga('send', 'pageview');
  </script>
<?php endif; ?>

JavaScript

这适用于 JavaScript:

  <script>
  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-<PUT YOUR GOOGLE ANALYTICS ID HERE>', 'auto');
    ga('send', 'pageview');
  }
  </script>

NiloVelez already said: Obviously, it won't make any real improvement, but if your only concern is getting a 100/100 score this will do it.

根据您对 Google 分析数据的使用,如果您需要基本信息(例如访问次数、UI 互动),您可能根本不包括 analytics.js,但仍然在 GA 中收集数据。

一个选项可能是在缓存的脚本中使用测量协议。 Google Analytics: Measurement Protocol Overview

当您将传输方式明确设置为图像时,您可以看到 GA 如何构建自己的图像信标。

ga('set', 'transport', 'image');

https://www.google-analytics.com/r/collect
  ?v={protocol-version}
  &tid={tracking-id}
  &cid={client-id}
  &t={hit-type}
  &dl={location}

您可以使用所需的负载创建自己的 GET 或 POST 请求。

但是,如果您需要更详细的信息,那可能不值得您付出努力。

您可以设置以 www.google-analytics.com 作为其源服务器的云端分发,并在云端分发设置中设置更长的有效期 header。然后在 Google 片段中修改该域。这可以防止您自己的服务器上的负载以及在 cron 作业中不断更新文件的需要。

这是设置和忘记。因此,如果有人 "copies" 您的代码段并窃取您的带宽,您可能希望向云端添加账单警报;-)

编辑:我试过了,但没那么容易,Cloudfront 通过 Cache-Control header 没有简单的方法来删除它

在新选项卡中打开 https://www.google-analytics.com/analytics.js 文件,复制所有代码。

现在在您的网站目录中创建一个文件夹,将其重命名为 google-analytics。

在同一个文件夹中创建一个文本文件并粘贴您在上面复制的所有代码。

重命名文件 ga-local.js

现在更改 URL 以在 Google 分析代码中调用本地托管的分析脚本文件。它看起来像这样,即 https://domain.xyz/google-analytics/ga.js

最后,将新的 google 分析代码放入网页的页脚。

你很高兴。现在检查您的 Google PageSpeed Insights 网站。它不会显示杠杆浏览器缓存 Google 分析的警告。此解决方案的唯一问题是,需要定期手动更新分析脚本。

2020 年 Page Speed Insights 用户代理是:"Chrome-Lighthouse" 移动设备和 "Google Page Speed Insights" 桌面设备。

<?php if (!isset($_SERVER['HTTP_USER_AGENT']) || stripos($_SERVER['HTTP_USER_AGENT'], 'Chrome-Lighthouse') === false  || stripos($_SERVER['HTTP_USER_AGENT'], 'Google Page Speed Insights') === false): ?>
// your google analytics code and other external script you want to hide from PageSpeed Insights here
<?php endif; ?>