Не удалось выполнить «postMessage» в «окне» GoogleTagManager - PullRequest
0 голосов
/ 31 августа 2018

Недавно я получил сообщение postMessage не может быть клонировано ошибка. Это происходит в большинстве современных браузеров, таких как Chrome 68, Firefox 61.0, IE11, Edge.

Не удалось выполнить 'postMessage' для 'Window': function (a){if(qe.$a.hasOwnProperty(a))return qe.$a[a]} не удалось клонировать.

Трассировка стека:

Ошибка: не удалось выполнить 'postMessage' для 'Window': function (a){if(qe.$a.hasOwnProperty(a))return qe.$a[a]} не удалось клонировать.
в _reportEvent (eval at (: 1: 35637),: 94: 35)
в eval (eval в (: 1: 35637),: 55: 5)
в eval (eval в (: 1: 35637),: 433: 11)

Поиск по источнику моей страницы в DevTools показывает gtm.js в качестве источника фрагмента кода:

gtm.js shown as source of the function

У меня есть код отслеживания Google Tag Manager на моей странице. Почему это происходит?

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Эти ошибки вызваны сканерами Facebook, выполняющими код JavaScript.

У меня были случаи появления этой ошибки с этих IP-адресов (все в диапазонах IP-адресов Facebook) и пользовательских агентов:

66.220.149.14 - Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0
  31.13.115.2 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
 173.252.87.1 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
69.171.251.11 - facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)

Чтобы получить актуальный список IP-адресов сканеров Facebook, см. Эту команду из https://developers.facebook.com/docs/sharing/webmasters/crawler/:

whois -h whois.radb.net -- '-i origin AS32934' | grep ^route

Вам потребуется обновить механизм сообщений об ошибках, чтобы отфильтровать ошибки из этих диапазонов IP-адресов.

Вы можете сделать это на стороне клиента в JavaScript, определив IP-адрес пользователя в случае ошибки (см. Как получить IP-адрес клиента с помощью JavaScript? ).

Или вы можете сделать это на стороне сервера. Вот пример для ASP.NET MVC:

using System.Linq;
// Requires the IPAddressRange NuGet library:
// https://www.nuget.org/packages/IPAddressRange/
using NetTools;

public class FacebookClientDetector
{
    /// <summary>
    /// The list of CIDR ranges of facebook IPs that its crawlers use.
    /// To generate, run
    ///     whois -h whois.radb.net -- '-i origin AS32934' | grep ^route
    /// https://developers.facebook.com/docs/sharing/webmasters/crawler/
    /// </summary>
    static readonly string[] facebookIpRanges = new string[] {
        "204.15.20.0/22",
        "69.63.176.0/20",
        "66.220.144.0/20",
        "66.220.144.0/21",
        "69.63.184.0/21",
        "69.63.176.0/21",
        "74.119.76.0/22",
        "69.171.255.0/24",
        "173.252.64.0/18",
        "69.171.224.0/19",
        "69.171.224.0/20",
        "103.4.96.0/22",
        "69.63.176.0/24",
        "173.252.64.0/19",
        "173.252.70.0/24",
        "31.13.64.0/18",
        "31.13.24.0/21",
        "66.220.152.0/21",
        "66.220.159.0/24",
        "69.171.239.0/24",
        "69.171.240.0/20",
        "31.13.64.0/19",
        "31.13.64.0/24",
        "31.13.65.0/24",
        "31.13.67.0/24",
        "31.13.68.0/24",
        "31.13.69.0/24",
        "31.13.70.0/24",
        "31.13.71.0/24",
        "31.13.72.0/24",
        "31.13.73.0/24",
        "31.13.74.0/24",
        "31.13.75.0/24",
        "31.13.76.0/24",
        "31.13.77.0/24",
        "31.13.96.0/19",
        "31.13.66.0/24",
        "173.252.96.0/19",
        "69.63.178.0/24",
        "31.13.78.0/24",
        "31.13.79.0/24",
        "31.13.80.0/24",
        "31.13.82.0/24",
        "31.13.83.0/24",
        "31.13.84.0/24",
        "31.13.85.0/24",
        "31.13.86.0/24",
        "31.13.87.0/24",
        "31.13.88.0/24",
        "31.13.89.0/24",
        "31.13.90.0/24",
        "31.13.91.0/24",
        "31.13.92.0/24",
        "31.13.93.0/24",
        "31.13.94.0/24",
        "31.13.95.0/24",
        "69.171.253.0/24",
        "69.63.186.0/24",
        "31.13.81.0/24",
        "179.60.192.0/22",
        "179.60.192.0/24",
        "179.60.193.0/24",
        "179.60.194.0/24",
        "179.60.195.0/24",
        "185.60.216.0/22",
        "45.64.40.0/22",
        "185.60.216.0/24",
        "185.60.217.0/24",
        "185.60.218.0/24",
        "185.60.219.0/24",
        "129.134.0.0/16",
        "157.240.0.0/16",
        "157.240.8.0/24",
        "157.240.0.0/24",
        "157.240.1.0/24",
        "157.240.2.0/24",
        "157.240.3.0/24",
        "157.240.4.0/24",
        "157.240.5.0/24",
        "157.240.6.0/24",
        "157.240.7.0/24",
        "157.240.9.0/24",
        "157.240.10.0/24",
        "157.240.16.0/24",
        "157.240.19.0/24",
        "157.240.11.0/24",
        "157.240.12.0/24",
        "157.240.13.0/24",
        "157.240.14.0/24",
        "157.240.15.0/24",
        "157.240.17.0/24",
        "157.240.18.0/24",
        "157.240.20.0/24",
        "157.240.21.0/24",
        "157.240.22.0/24",
        "157.240.23.0/24",
        "129.134.0.0/17",
        "157.240.0.0/17",
        "69.171.250.0/24",
        "204.15.20.0/22",
        "69.63.176.0/20",
        "69.63.176.0/21",
        "69.63.184.0/21",
        "66.220.144.0/20",
        "69.63.176.0/20",
    };

    public static bool IsFacebookClient(string ip)
    {
        IPAddressRange parsedIp;
        if (!IPAddressRange.TryParse(ip, out parsedIp)) {
            return false;
        }

        return facebookIpRanges.Any(cidr => IPAddressRange.Parse(cidr).Contains(parsedIp));
    }
}
0 голосов
/ 07 сентября 2018

Это происходит постоянно, если что-то не может быть продублировано алгоритмом структурированного клона . Этот алгоритм используется window.postMessage. Если мы читаем документацию из window.postMessage для первого параметра:

сообщение
Данные для отправки в другое окно. Данные сериализуются с использованием алгоритма структурированного клона .

и затем откройте описание из алгоритма структурированного клона (см. Последнюю ссылку выше), тогда мы можем прочитать:

Алгоритм структурированного клонирования - это алгоритм, определенный в спецификации HTML5 для копирования сложных объектов JavaScript. Он используется внутри системы при передаче данных в Workers и из него через postMessage() или при хранении объектов с помощью IndexedDB. Он создает клон путем повторения через входной объект, сохраняя карту ранее посещенных ссылок, чтобы избежать бесконечных циклов обхода.

Вещи, которые не работают со структурированным клоном

  • Error и Function не могут дублироваться алгоритмом структурированного клона; попытка сделать это бросит DATA_CLONE_ERR исключение.
  • Попытка клонировать DOM узлов также вызовет исключение DATA_CLONE_ERR.
  • Некоторые параметры объектов не сохраняются:

    • Поле lastIndex объектов RegExp не сохраняется.
    • Дескрипторы свойств, установщики и получатели (а также аналогичные функции, подобные метаданным), не дублируются. Например, если объект помечен только для чтения с использованием дескриптора свойства, он будет доступен для чтения и записи в дубликате, так как это условие по умолчанию.
    • Цепочка прототипов не обходит и не дублируется.

Поддерживаемые типы

Я проверил это с некоторыми объектами, и я могу показать вам следующие примеры, когда это происходит ...

Пример с пользовательской функцией

var obj = {something: function(){}};
window.postMessage(obj, '*'); // DataCloneError

Пример с встроенной функцией

var obj = {something: window.alert};
window.postMessage(obj, '*'); // DataCloneError

То же самое мы увидим с нативными функциями, такими как Boolean, Date, String, RegExp, Number, Array.

Пример с собственным объектом

var obj = {something: document};
window.postMessage(obj, '*'); // DataCloneError

Пример с объектом HTML-элемента

var obj = {something: document.createElement('b')};
window.postMessage(obj, '*'); // DataCloneError

Мы могли бы написать больше примеров, если бы прочитали описание Выше приведен алгоритм структурированного клона , но я думаю, что здесь этого достаточно.

Что мы можем сделать, чтобы избежать этой ошибки

В нашем коде мы могли использовать только поддерживаемые типы (см. Список выше) в наших объектах. Но не в нашем коде мы должны связаться с разработчиками из этого кода и написать им, как они должны исправить свой код. В случае из Google Tag Manager вы можете написать это на Официальном форуме Google Tag Manager с описанием того, как они должны исправить свой код.

Обходной путь для некоторых браузеров

В некоторых браузерах вы не можете переопределять собственные методы по соображениям безопасности. Например, IE не позволяет переопределить window.postMessage. Но другие браузеры, такие как Chrome, позволяют переопределить этот метод следующим образом:

var postMessageTemp = window.postMessage;
window.postMessage = function(message, targetOrigin, transfer)
{
    postMessageTemp(JSON.parse(JSON.stringify(message)), targetOrigin, transfer)
};

Но обратите внимание, что window является глобальным объектом контекста JavaScript и не создается из prototype. Другими словами: вы не можете переопределить его с помощью window.prototype.postMessage = ....

Пример с обходным решением

var obj = {something: window};

var postMessageTemp = window.postMessage;
window.postMessage = function(message, targetOrigin, transfer)
{
    function cloneObject(obj)
    {
        var clone = {};
        for(var i in obj)
        {
            if(typeof(obj[i]) == 'object' && obj[i] != null)
            {
                if((''+obj[i]) == '[object Window]')
                {
                    delete obj[i];
                    continue;
                }

                clone[i] = cloneObject(obj[i]);
            }
            else
                clone[i] = obj[i];
        }
        return clone;
    }

    // to avoid weird error causing by window object by JSON.stringify() execution.
    var clone = cloneObject(message);

    postMessageTemp(JSON.parse(JSON.stringify(clone)), targetOrigin, transfer)
};

window.postMessage(obj, '*');

console.log('We do not have any errors.');

Как реализовать этот обходной путь

Поместите эту переопределенную функцию window.postMessage в часть скрипта на своей HTML-странице перед скриптом Google Tag Manager. Но вы могли бы помочь разработчикам из Google Tag Manager понять и исправить эту ошибку, а также подождать исправленный скрипт Google Tag Manager.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...