前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GA源代码里的小技巧之Beacon请求

GA源代码里的小技巧之Beacon请求

作者头像
mmzhou
发布2018-08-01 18:47:45
1.3K0
发布2018-08-01 18:47:45
举报
文章被收录于专栏:前端小作坊前端小作坊

GA源代码里的小技巧之Beacon请求

作者前段时间在做类似Google Analytics(以下简称GA)的第三方监控脚本。所以对GA的前端代码做过调研,对GA的压缩后代码做了一定程度上的人肉美化。这里美化的是analytics.js的j41版本,本文提到的小技巧也是基于这个版本的js。

智能Beacon

GA监控脚本一般都放在开发者的网页上。域名往往和Google不一样,这样发送请求到Google服务器的时候会涉及到跨域。普通的Ajax请求是做不到的,通常称这种请求为beacon或是ping。业内常用的一个方案是发送一个图片请求(GET方式),将请求参数放在图片请求的地址后面。例如:

代码语言:javascript
复制
https://www./r/collect?v=1&_v=j46&a=134081920&t=pageview&_s=1&dl=http%3A%2F%2Fzencode.in%2F&ul=zh-cn&de=UTF-8&dt=MZhou%27s%20blog%20-%20Taste%20of%20life.&sd=24-bit&sr=1280x800&vp=481x676&je=0&fl=22.0%20r0&_utma=9582782.1438874051.1425021219.1431473728.1471631422.8&_utmz=9582782.1471631422.8.1.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)&_utmht=1473782171819&_u=QACCAAABI~&jid=633265686&cid=1438874051.1425021219&tid=UA-36422454-1&_r=1&gtm=GTM-MP42BH&z=300649187

因为通常第三方监控请求没有很强的安全要求(不会发送密码、密钥之类的信息),所以使用图片请求将请求参数放在地址里面也是OK的。示例代码如下:

代码语言:javascript
复制
function imgPing(url, callback) {
    var key = '__SOME_RANDOM_KEY__' + (+new Date());
    var img = new Image();
    window[key] = img;
    img.onload = img.onerror = img.onabort = function () {
        img.onload = img.onerror = img.onabort = null;
        window[key] = null;
        img = null;
        if (callback) {
            callback();
        }
    };
    img.src = concatUrl;
    return true;
}

图片请求是GET请求,参数放在URL地址中,而URL地址的长度是有一定限制的。规范对URL长度并没有要求,但是浏览器、服务器、代理服务器都URL对长度有要求。例如:IE6、7、8(部分)的URL长度不能超过2083的字符长度,URL中的path部分不能超过2048。这就导致有些请求会发送不完全。

为了解决这个问题可以使用XMLHttpRequest(简称XHR)来发送跨域POST请求。当然这需要浏览器的跨域支持。发送POST请求时,参数都放在请求的payload中,不会受到URL长度所限制。但因为是POST请求,所以需要协议头部比GET方法多一点点,消耗也稍高。示例代码如下:

代码语言:javascript
复制
function xhrPing(url, params, callback) {
    if (hasCors()) {
        return;
    }

    var xhr = new window.XMLHttpRequest();
    xhr.open('POST', url, true);
    xhr.withCredentials = true;
    xhr.setRequestHeader('Content-Type', 'text/plain');
    if (callback) {
        xhr.onreadystatechange = function () {
            if (xhr.readyState !== 4) {
                return;
            }

            var status = xhr.status;
            var isSuccess = status >= 200 && status < 400;
            var error = null;
            if (!isSuccess) {
                error = new Error();
            }
            callback(error);
        };
    }
    xhr.send(params);
};

除了这两种方法之外,浏览器还提供了一个标准的用于发送beacon的方法:[navigator.sendBeacon](http://)。这个方法本质上和跨域的XHR请求没有多大区别,但是sendBeacon方法能够确保在页面关闭的时候还能发送成功。这也是它的最大优势。示例代码如下:

代码语言:javascript
复制
function beaconPing(url, params) {
    if (hasSendBeacon()) {
        return window.navigator.sendBeacon(url, params);
    }
    else {
        return false;
    }
};

sendBeacon出现之前,为了能够在页面关闭时发送beacon,常用的方法是两种:

  1. 先发送一个图片的beacon,然后死循环200ms左右来提高beacon请求发送成功的概率
  2. 发送同步的XHR请求,确保页面要等到XHR请求结束后才能关闭。不过同步XHR已经被W3C标准定义为不推荐使用了: Synchronous XMLHttpRequest outside of workers is in the process of being removed from the web platform as it has detrimental effects to the end user's experience. (This is a long process that takes many years.) Developers must not pass false for the async argument when entry settings object's global object is a Window object. User agents are strongly encouraged to warn about such usage in developer tools and may experiment with throwing an InvalidAccessError exception when it occurs.

综合上面的讨论给出如下的对比表格:

方法

优点

缺点

图片请求

1. GET请求头部少,快2. 支持广

1. URL长度限制2. 需要延迟关闭才能用于unload发送

sendBeacon

1. unload时更能确保成功2. 支持发送更多数据

1. POST请求消耗多2. 旧浏览器支持少

XHR CORS

支持发送更多数据

1. POST请求消耗多2. 旧浏览器支持少3. unload时不能使用

如果没有指定发送方法,那么GA会在URL字符长度不超长时使用图片beacon的方式发送。如果超过了则尝试使用sendBeacon方法发送beacon请求,如果不支持sendBeacon则会采用跨域XHR发送。如果跨域XHR不支持则最后fallback到图片发送。实际代码如下:

代码语言:javascript
复制
var smartPing = function(api, param, callback) {
    callback = callback || noop;
    if (2036 >= param.length) {
        imgPing(api, param, callback);
    } else if (8192 >= param.length) {
        beaconPing(api, param, callback) || xhrPing(api, param, callback) || imgPing(api, param, callback);
    } else {
        errorPing('len', param.length);
        throw new OverLengthError(param.length);
    }
};

当然GA的做法并非最优,因为非IE6、7的浏览器图片请求发送的数据可以超过2083。如果真的有很多数据需要发送,那么我们可以合并短请求、拆分长请求。

资料:

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • GA源代码里的小技巧之Beacon请求
    • 智能Beacon
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
    http://www.vxiaotou.com