Не удалось выполнить postMessage в окне GoogleTagManager

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

Failed to execute 'postMessage' on 'Window': function (a){if (qe.$a.hasOwnProperty(a))return qe.$a[a]} could not be cloned.

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

Error: Failed to execute 'postMessage' on 'Window': function (a){if (qe.$a.hasOwnProperty(a))return qe.$a[a]} could not be cloned.
at _reportEvent (eval at (:1:35637), :94:35)
at eval (eval at (:1:35637), :55:5)
at eval (eval at (:1:35637), :433:11)

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

Не удалось выполнить postMessage в окне GoogleTagManager

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

Я только начал видеть эту ошибку в нашем приложении несколько дней назад, хотя мы не внесли изменений в код. Это происходит во всех основных браузерах (Chrome 68, Firefox, Edge 17), но только в Windows.

jessica 01.09.2018 00:23

Я также недавно начал видеть эту ошибку - в Linux + Chrome, iOS + Safari, Windows + Chrome. Мы только недавно добавили в наше приложение Диспетчер тегов Google. Следующая строка трассировки стека - at _reportEvent.

Yoshi 04.09.2018 02:08

Первое, что мы говорим, было 2018-08-30T17: 13 UTC. Кажется, есть во всех браузерах / устройствах, и мы также проследили это до GTM.

R Menke 05.09.2018 07:36

Следующее может помочь: stackoverflow.com/questions/42376464/…

Danie Schoeman 05.09.2018 08:12

@DanieSchoeman видел это, но поскольку этой ошибки нет в коде GTM, мы не можем исправить ее таким образом. Я думаю?

R Menke 05.09.2018 08:15

исправление: ... поскольку эта ошибка находится в коде GTM ...

R Menke 05.09.2018 08:43

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

Michael M 05.09.2018 09:19

На случай, если это поможет выяснить причину: единственный активный код отслеживания в моем GTM - для Facebook Pixel. Существует также код отслеживания Pardot, однако он не активен для имени хоста, в котором возникают ошибки. Я также отредактировал вопрос, добавив трассировку стека, которая показывает, что ошибка является анонимным блоком кода.

Yoshi 05.09.2018 10:05

Я отредактировал вопрос, включив в него снимок экрана, показывающий gtm.js как источник функции.

Yoshi 05.09.2018 10:19

@MichaelM включает ли ваш gtm.js соответствующую функцию (см. Снимок экрана в отредактированном вопросе)? Я не получаю эту ошибку в каждом клиенте (я не могу ее воспроизвести). Так что окружающая среда, наверное, актуальна.

Yoshi 05.09.2018 10:20

Нашел еще один список вещей, которые могут вызвать проблемы, которые могут вызвать проблемы: analyticsmania.com/post/… и analyticsmania.com/post/google-tag-manager-404-error-gtm-js

Danie Schoeman 05.09.2018 15:16

Вполне может быть, что [(a)), [a] или $ a] пусто по той или иной причине: (a) {if (qe. $ A.hasOwnProperty (a)) return qe. $ A [ а]}

Danie Schoeman 05.09.2018 15:18

Я вижу это в библиотеках Javascript Microsoft Power BI.

James Webster 10.09.2018 07:51
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
27
13
12 011
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

message
Data to be sent to the other window. The data is serialized using the structured clone algorithm.

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

The structured clone algorithm is an algorithm defined by the HTML5 specification for copying complex JavaScript objects. It is used internally when transferring data to and from Workers via postMessage() or when storing objects with IndexedDB. It builds up a clone by recursing through the input object while maintaining a map of previously visited references in order to avoid infinitely traversing cycles.

Things that don't work with structured clone

  • Error and Function objects cannot be duplicated by the structured clone algorithm; attempting to do so will throw a DATA_CLONE_ERR exception.

  • Attempting to clone DOM nodes will likewise throw a DATA_CLONE_ERR exception.

  • Certain parameters of objects are not preserved:

    • The lastIndex field of RegExp objects is not preserved.
    • Property descriptors, setters, and getters (as well as similar metadata-like features) are not duplicated. For example, if an object is marked read-only using a property descriptor, it will be read-write in the duplicate, since that's the default condition.
    • The prototype chain does not get walked and duplicated.

Supported types

  • All primitive types(Note: However not symbols)
  • Boolean object
  • String object
  • Date
  • RegExp(Note: The lastIndex field is not preserved.)
  • Blob
  • File
  • FileList
  • ArrayBuffer
  • ArrayBufferView(Note: This basically means all typed arrays like Int32Array etc.)
  • ImageData
  • Array
  • Object(Note: This just includes plain objects (e.g. from object literals))
  • Map
  • Set

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

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

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 вы можете записать его в официальный форум 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.info('We do not have any errors.');

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

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

Похоже, кто-то разместил вопрос на форуме GTM: productforums.google.com/forum/#!topic/tag-manager/…

Yoshi 10.09.2018 07:20

@Yoshi, но это тот же вопрос, что и от OP, и никто не ответил на этот вопрос. Это было скопировано из нашего вопроса до того, как мы ответили на этот вопрос. Может быть, кто-то захотел заработать на этом награду.

Bharata 10.09.2018 09:47

Привет, Бхарата, спасибо за прекрасный ответ. Как вы показали несколько причин, почему это происходит, и это приемлемо, поскольку я пробовал их со своей стороны. Основная проблема, с которой я сталкиваюсь, заключается в том, что ошибка не возникает ни на одном из устройств, на которых я ее тестирую. Как вы предложили, я могу попробовать метод перезаписи, но, опять же, могу только предположить, что он работает. Надеюсь, что это работает.

cris 13.09.2018 23:38

@cris причина, по которой вы можете не увидеть его на своих устройствах, заключается в том, что он исходит от сканеров Facebook. Смотрите мой дополнительный ответ.

Yoshi 26.09.2018 06:39

Ты классный друг

ivar ajet 20.01.2020 08:03

@NadeemAhmad, я думаю, вы что-то неправильно поняли. Может быть, вы выполнили один из 4 первых фрагментов со строкой кода window.postMessage(obj, '*'); // DataCloneError? В этом случае это должна быть ошибка. Я не зря написал туда комментарий. Только в последнем фрагменте есть решение. Вы это неправильно поняли?

Bharata 21.09.2020 21:09

@Bharata да, я попробовал фрагмент временного решения. Я передал большой кусок объекта, и это вызвало это.

Nadeem Ahmad 22.09.2020 15:44

@NadeemAhmad, не могли бы вы опубликовать свой полный код с этим большим фрагментом объекта на каком-нибудь сайте вроде codepen.io, пожалуйста? Мне нужна ссылка на этот код, чтобы исправить мой код.

Bharata 23.09.2020 16:13

@NadeemAhmad, если вы не можете воспроизвести свою ошибку, то не хотели бы вы отозвать мой ответ, потому что я написал свой ответ очень старательно и ответственно. И я не могу понять, почему я получил за это голос против. Даже если вы получили одну ошибку, это не повод для отрицательного голоса - я не могу знать все ситуации.

Bharata 28.09.2020 19:53

Эти ошибки вызваны поисковыми роботами 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));
    }
}

Понятия не имею, как Facebook сканирует веб-сайты, но разве не странно видеть, что ошибка возникает в нескольких браузерах / устройствах, если все они исходят от поисковых роботов Facebook?

R Menke 26.09.2018 11:39

@RMenke Хороший улов. Разве это не ошибки, исходящие от фреймов, загружаемых Facebook в Instagram и Facebook?

Yoan Tournade 05.10.2018 17:13

@RMenke это странно, но данные не лгут - см. Мой отредактированный ответ для моих журналов IP-адресов facebook, вызывающих ошибку на смешанных платформах / браузерах

Yoshi 09.10.2018 02:36

Вы можете получить всегда актуальный список IP-адресов сканера Facebook с whois -h whois.radb.net -- '-i origin AS32934' | grep ^route developers.facebook.com/docs/sharing/webmasters/crawler

Jake 18.10.2018 21:48

@ Джейк, спасибо. Я обновил свой ответ, включив в него эту команду и пример кода использования записей CIDR.

Yoshi 29.10.2018 23:33

Вы можете стать жертвой путаницы, которую я испытал при использовании сервис-воркеров через Окно рабочего окна. Этот пакет использует два разных экземпляра своих модулей. Есть набор статических модулей. Также есть еще один набор, находящийся под зонтиком основного модуля Workbox. Они внутренне вызывают свои статические аналоги

var payload = {key: "value"},

{ Workbox, messageSW } = await import('workbox-window'), // these represent static modules without a contextual `this`

wb = new Workbox('/service-worker.js'); // calls to this works on a single instance that interfaces with the underlying static equivalents

Это означает, что пока вам нужно сделать

messageSW(wb.getSW(), payload);

Вызов wb.messageSW(wb.getSW(), payload) приводит к ошибке OP, потому что фактическая полезная нагрузка здесь - это циклический сервис-воркер, а не полезная нагрузка нашего литерала объекта. Созданная версия в этом случае будет работать с:

wb.messageSW( payload);

Другие вопросы по теме