web-dev-qa-db-fra.com

Impossible d'exécuter 'postMessage' sur GoogleTagManager 'Window'

Récemment, j'obtiens cette erreur postMessage ne peut pas être clonée . Cela se produit sur la plupart des navigateurs les plus récents tels que Chrome 68, Firefox 61.0, IE11, Edge).

Échec de l'exécution de 'postMessage' sur 'Window': function (a){if(qe.$a.hasOwnProperty(a))return qe.$a[a]} n'a pas pu être cloné.

La trace de la pile est:

Erreur: Impossible d'exécuter 'postMessage' sur 'Window': function (a){if(qe.$a.hasOwnProperty(a))return qe.$a[a]} n'a pas pu être cloné.
at _reportEvent (à l’évaluation: (: 1: 35637),: 94: 35)
at eval (évaluation à (: 1: 35637),: 55: 5)
at eval (évaluation à (: 1: 35637),: 433: 11)

La recherche dans la source de ma page dans DevTools montre gtm.js comme source du fragment de code:

gtm.js shown as source of the function

J'ai un code de suivi Google Tag Manager sur ma page. Pourquoi cela arrive-t-il?

26
cris

Cela se produit tout le temps, si quelque chose ne peut pas être dupliqué par le algorithme de clone structuré. Cet algorithme est utilisé par window.postMessage. Si nous lisons la documentation à partir de window.postMessage pour le premier paramètre:

message
Données à envoyer à l’autre fenêtre. Les données sont sérialisées à l'aide de algorithme de clone structuré .

puis ouvrez la description de algorithme de clone structuré (voir dernier lien ci-dessus), puis on peut lire:

L'algorithme de clone structuré est un algorithme défini par la spécification HTML5 pour la copie d'objets JavaScript complexes. Il est utilisé en interne lors du transfert de données depuis et vers les travailleurs via postMessage() ou lors du stockage d'objets avec IndexedDB. Il construit un clone en récursant à travers l'objet d'entrée tout en conservant une carte des références précédemment visitées afin d'éviter des cycles de parcours infinis.

Ce qui ne fonctionne pas avec un clone structuré

  • Les objets Error et Function ne peuvent pas être dupliqués par l'algorithme de clone structuré; tenter de le faire lève une exception DATA_CLONE_ERR.
  • Tenter de cloner DOM nœuds lève également une exception DATA_CLONE_ERR.
  • Certains paramètres d'objets ne sont pas conservés:

    • Le champ lastIndex des objets RegExp n'est pas préservé.
    • Les descripteurs de propriété, les setters et les getters (ainsi que les fonctionnalités similaires à des métadonnées) ne sont pas dupliqués. Par exemple, si un objet est marqué en lecture seule à l'aide d'un descripteur de propriété, il sera en lecture-écriture dans la copie, puisqu'il s'agit de la condition par défaut.
    • La chaîne de prototypes ne fait pas l’objet d’une duplication.

Types pris en charge

Je l'ai testé avec quelques objets et je peux vous montrer les exemples suivants lorsque cela se produit ...

Exemple avec une fonction personnalisée

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

Exemple avec fonction native

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

La même chose que nous verrons avec des fonctions natives comme Boolean, Date, String, RegExp, Number, Array .

Exemple avec un objet natif

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

Exemple avec un objet d'élément HTML

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

Nous pourrions écrire plus d'exemples si nous lisons la description de L'algorithme de clone structuré ci-dessus, mais je pense que cela suffit.

Ce que nous pourrions faire pour éviter cette erreur

Dans notre code, nous ne pouvions utiliser que les types supportés (voir la liste ci-dessus) dans nos objets. Mais dans notre code, nous devons contacter les développeurs de ce code et leur écrire comment ils doivent corriger leur code. Dans le cas de Google Tag Manager, vous pouvez l'écrire en le forum officiel de Google Tag Manager avec une description de la manière dont ils doivent corriger leur code.

Solution de contournement pour certains navigateurs

Dans certains navigateurs, vous ne pouvez pas remplacer les méthodes natives pour des raisons de sécurité. Par exemple IE ne permet pas de remplacer window.postMessage. Mais d’autres navigateurs tels que Chrome permettent de remplacer cette méthode comme suit:

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

Mais notez que window est un objet global du contexte JavaScript et qu'il n'est pas créé à partir de prototype. En d'autres termes: vous ne pouvez pas le remplacer par window.prototype.postMessage = ....

Exemple avec solution de contournement

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.');

Comment implémenter cette solution de contournement

S'il vous plaît mettez cette fonction window.postMessage Surchargée dans la partie script de votre page HTML avant le script Google Tag Manager. Mais, mieux, vous pourriez aider les développeurs de Google Tag Manager à comprendre et à corriger cette erreur et vous pouvez attendre le script corrigé de Google Tag Manager.

13
Bharata

Ces erreurs sont causées par les robots Facebook qui exécutent du code JavaScript.

J'ai eu des occurrences de cette erreur de ces adresses IP (toutes dans les plages d'IP de Facebook) et des agents d'utilisateur:

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)

Pour obtenir une liste à jour des adresses IP des robots Facebook, consultez cette commande dans https://developers.facebook.com/docs/sharing/webmasters/crawler/ :

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

Vous devrez mettre à jour votre mécanisme de rapport d'erreur pour filtrer les erreurs de ces plages IP.

Vous pouvez le faire côté client en JavaScript en déterminant l'adresse IP de l'utilisateur en cas d'erreur (voir Comment obtenir l'adresse IP du client à l'aide de JavaScript? ).

Ou vous pouvez le faire côté serveur. Voici un exemple pour 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));
    }
}
7
Yoshi