在页面重定向之前,如何确保服务器请求完成?

时间:2011-07-26 21:48:05

标签: javascript google-analytics xmlhttprequest

编辑:为了澄清,我的主要问题归结为:如果您向某个服务器(在本例中为Google)发出AJAX请求,但客户端会在服务器之前离开该页面完成请求,是否有可能(或可能)服务器也会中止请求,或服务器是否会尝试完成请求(尽管没有人再响应)?

如果您愿意,请随意阅读所有细节的其余部分。


我正在一个旨在立即重定向的网页上使用Google Analytics。由于Google javascript文件ga.js是异步加载的,因此我需要确保跟踪javascript动态添加的所有脚本标记,并且只有在这些脚本完成后才会发生页面重定向。我已经处理了那部分。

文件ga.js似乎向带有参数的__utm.gif文件发出请求,这是执行实际跟踪的内容。该请求显然不是来自我可以控制的文件,所以这是我的问题:

首先,请求是异步的(我怀疑它是)?其次,在重定向页面之前,如何确保该请求有时间完成(我希望在“足够的时间”过后不再简单地重定向)?如果在请求完成之前重定向原始页面,请求是否仍然完成(毕竟,我不需要Google提供任何数据)?

编辑:这是我的代码:     

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
     <title>Redirecting...</title>

     <script type="text/javascript">
        /* <![CDATA[ */

        // Holds a value for each script. When all the values contained in this array are true, all loading has completed.
        var scripts = [];

        function scriptDetectLoaded(script)
        {
            scripts.push({ loaded: false, element: script });
            var index = scripts.length - 1;

            // Will set this script as loaded
            var callback = function ()
            {
                //console.log("Script with index " + index + " finished loading");
                scripts[index].loaded = true;
            };

            // For most browsers
            script.onload = callback;
            // For IE
            script.onreadystatechange = function ()
            {
                if (this.readyState == "complete")
                    callback();
            };

            return index;
        }

        /* ]]> */
     </script>

     <!-- Google analytics code -->
     <script type="text/javascript">
        /* <![CDATA[ */
        var _gaq = _gaq || [];
        _gaq.push(['_setAccount', 'UA-MY_ID-1']);
        _gaq.push(['_trackPageview']);

        (function ()
        {
            //debugger;
            var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
            ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
            scriptDetectLoaded(ga); var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
        })();
        /* ]]> */
    </script>
</head>
<body>
    <noscript>
        <p>Please enable JavaScript and refresh this page. Our site won't work correctly without it.</p>
        <p><a href="http://www.google.com/search?q=how+to+enable+javascript" target="_blank">How do I enable JavaScript?</a></p>
    </noscript>

<!-- Google Code for New Account Conversion Page -->
<script type="text/javascript">
    /* <![CDATA[ */
    //debugger;
    var google_conversion_id = SOME_ID;
    var google_conversion_language = "en";
    var google_conversion_format = "2";
    var google_conversion_color = "ffffff";
    var google_conversion_label = "SOME_LABEL";
    var google_conversion_value = 0;

    (function () {
        var gad = document.createElement('script'); gad.type = 'text/javascript'; gad.async = true;
        gad.src = document.location.protocol + "//www.googleadservices.com/pagead/conversion.js";
        scriptDetectLoaded(gad); var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(gad, s);
    })();
    /* ]]> */
</script>
<noscript>
    <div style="display:inline;">
        <img height="1" width="1" style="border-style:none;" alt="" src="http://www.googleadservices.com/pagead/conversion/1056222251/?label=keCSCNO9qAIQq9jS9wM&amp;guid=ON&amp;script=0"/>
    </div>
</noscript>

    <!-- Redirect Page -->
    <script type="text/javascript">
        /* <![CDATA[ */
        //debugger;
        var url = '/console';
        var interval = 100 /*milliseconds*/;
        var timeout = 5000 /*milliseconds*/;
        var count = 0;

        // Set a repeating function that checks to ensure all the scripts have loaded.
        // Once all the scripts have loaded, redirect the page.
        var id = setInterval(function ()
        {
            count += interval;

            // Check for timeout
            if (count > timeout)
            {
                //console.log("Timed out.");
                redirect();
            }

            // Check to make sure all scripts have loaded
            for (var i = 0, len = scripts.length; i < len; i++)
            {
                if (!scripts[i].loaded)
                    return;
            }

            // If we make it here, redirect
            redirect();
        }, interval);

        function redirect()
        {
            location.replace(url);

            // Run this in case the page doesn't redirect properly.
            clearInterval(id);

            var a = document.createElement("a");
            a.href = url;
            a.innerHTML = "Please click here to proceed";

            var p = document.getElementById("message");
            p.innerHTML = "";
            p.appendChild(a);
        }
        /* ]]> */
    </script>

    <p id="message">Please wait as we redirect the page.</p>
</body>
</html>

3 个答案:

答案 0 :(得分:1)

如果您在请求完成之前重定向,它将在客户端被取消。意思是,服务器可能已经获得了帖子并对其采取了行动,但是你不会得到结果。如果这些项是动态添加的,则不能使用任何onload类型的函数。我会想象你添加的谷歌文件会有一些你可以用来重定向你的回调。

编辑:如果你想以一种你将完全知道何时完成加载的方式加载脚本,这样你就可以重定向到另一个页面,我将使用jquery的$ .getScript函数。它允许在文件加载后进行回调,然后您可以立即重定向api.jquery.com/jQuery.getScript

答案 1 :(得分:0)

对于依赖于__utm.gif的跟踪,不需要完成请求以使度量标准生效。一旦浏览器发送请求(包含所有参数),GA就能满足它的需求。所以你只需要确保图像请求触发。

如果这是一个没有真实内容的插页式页面,您可以执行诸如检查文档图像集合的长度等操作;当长度> 0,那么你知道GA创建了IMG并设置了它的src(从而触发了请求)。不确定该集合的细节,但我知道过去存在的东西;也许它仍然存在。在这种情况下,执行测试并启动重定向的简单setInterval就足够了。

编辑:由于GA的东西会在文档中添加脚本,因此您可以检查DOM结构以查看是否存在具有正确src值的脚本。这可能会让你更接近于从正确的事件中链接重定向。

答案 2 :(得分:0)

对于当前的ga.js状态,您可以使用以下代码检查跟踪完成情况:

(function (global) {

    var listeners = []
        , ImageReworked
        , ImageNative = Image
    ;

    function stringMatch(haystack, needle) {
        if (typeof needle.valueOf() === 'string' && haystack.indexOf(needle) !== -1) {
            return true;
        } else if (needle instanceof RegExp && haystack.match(needle)) {
            return true;
        }
    }

    global.addImageListener = function (url, handler) {
        if (!listeners.length) {
            Image = ImageReworked;
        }
        listeners.push([url, handler]);
    };

    global.removeImageListener = function (url, handler) {
        var newListeners = [];
        listeners.forEach(function (el) {
            if (url.constructor !== el[0].constructor //this will not work for object in different windows
                || el[0].toString() !== url.toString()
                || (handler && handler !== el[1])) {
                newListeners.push(el);
            }
        });
        listeners = newListeners;
        if (!listeners.length) {
            Image = ImageNative;
        }
    };

    ImageReworked = function(w, h) {
        var i = new ImageNative(w, h)
        ;

        function handler() {
            listeners.forEach(function (el) {
                var url = el[0]
                    , handler = el[1]
                ;

                if (stringMatch(i.src, url)) {
                    handler(i.src);
                }
            });
        }

        if (i.addEventListener) {
            i.addEventListener('load', handler, false);
        } else if (i.attachEvent) {
            i.attachEvent('onload', handler);
        }

        return i;
    };
})(window);

用法示例:

addImageListener(/__utm/, function (src) {
    var parameters = {};

    window.removeImageListener(new RegExp('__utm'));//see, regexp can be created by new RegExp!

    (foundParameters = src.match(/(\?|&)(.*?\=[^?&]*)/g)) && foundParameters.forEach(function (parameter) {
        var pair = parameter.replace(/^(\?|&)/, '').split('=');
        parameters[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
    });
    console.log(parameters);
});

_gaq.push(['_setAccount', gaid], ['_trackPageview']);

但是你应该记住,如果GA更改了他们的跟踪逻辑,那么这段代码就会被破坏。

你还应该添加超时(如果加载事件永远不会发生的话)。

并且不要使用i.onload,因为GA脚本会覆盖此属性。