javascript - attribute - Error al ejecutar ''postMessage'' en ''Window'' GoogleTagManager
google tag manager (2)
Esto sucede todo el tiempo, si algo no puede ser duplicado por el algoritmo de clonación estructurada . Este algoritmo es utilizado por window.postMessage
. Si leemos la documentación de window.postMessage
para el primer parámetro:
mensaje
Datos a enviar a la otra ventana. Los datos se serializan utilizando el algoritmo de clonación estructurada .
y luego abra la descripción del algoritmo de clonación estructurada (vea el último enlace arriba) luego podemos leer:
El algoritmo de clonación estructurada es un algoritmo definido por la especificación HTML5 para copiar objetos complejos de JavaScript. Se usa internamente al transferir datos hacia y desde Trabajadores a través de
postMessage()
o al almacenar objetos conIndexedDB
. Construye un clon recurriendo a través del objeto de entrada mientras mantiene un mapa de las referencias visitadas previamente para evitar ciclos de desplazamiento infinitos.Cosas que no funcionan con clones estructurados.
Function
objetos deError
yFunction
no pueden ser duplicados por el algoritmo de clonación estructurada; intentar hacerlo lanzará una excepciónDATA_CLONE_ERR
.- Intentar clonar los nodos
DOM
también lanzará una excepciónDATA_CLONE_ERR
.Ciertos parámetros de los objetos no se conservan:
- El campo
lastIndex
de los objetosRegExp
no se conserva.- Los descriptores de propiedades, los definidores y los captadores (así como las características similares a metadatos similares) no están duplicados. Por ejemplo, si un objeto se marca de solo lectura con un descriptor de propiedad, se leerá y escribirá en el duplicado, ya que esa es la condición predeterminada.
- La cadena del prototipo no se camina y se duplica.
Tipos soportados
- Todos los tipos primitivos (Nota: Sin embargo, no símbolos)
- Objeto
Boolean
- Objeto de
String
Date
RegExp
(Nota: el campo lastIndex no se conserva)Blob
File
FileList
ArrayBuffer
ArrayBufferView
(Nota: Básicamente, esto significa todas las matrices escritas como Int32Array, etc.)ImageData
Array
Object
(Nota: Esto solo incluye objetos planos (por ejemplo, de literales de objetos))Map
Set
Lo probé con algunos objetos y puedo mostrarte los siguientes ejemplos cuando esto suceda ...
Ejemplo con función personalizada
var obj = {something: function(){}};
window.postMessage(obj, ''*''); // DataCloneError
Ejemplo con función nativa.
var obj = {something: window.alert};
window.postMessage(obj, ''*''); // DataCloneError
Lo mismo veremos con funciones nativas como Boolean
, Date
, String
, RegExp
, Number
, Array
.
Ejemplo con objeto nativo
var obj = {something: document};
window.postMessage(obj, ''*''); // DataCloneError
Ejemplo con objeto elemento HTML
var obj = {something: document.createElement(''b'')};
window.postMessage(obj, ''*''); // DataCloneError
Podríamos escribir más ejemplos si leemos la descripción del algoritmo de clonación estructurada anterior, pero creo que aquí es suficiente.
Qué podríamos hacer para evitar este error.
En nuestro código solo podríamos usar tipos compatibles (consulte la lista anterior) en nuestros objetos. Pero no en nuestro código tenemos que contactar a los desarrolladores de este código y escribirles cómo tienen que corregir su código. En el caso de Google Tag Manager, puede escribirlo en el Foro oficial de Google Tag Manager con una descripción de cómo deben corregir su código.
Solución para algunos navegadores.
En algunos navegadores no se pueden anular los métodos nativos por razones de seguridad. Por ejemplo, IE no permite anular window.postMessage
. Pero otros navegadores como Chrome permiten anular este método de la siguiente manera:
var postMessageTemp = window.postMessage;
window.postMessage = function(message, targetOrigin, transfer)
{
postMessageTemp(JSON.parse(JSON.stringify(message)), targetOrigin, transfer)
};
Pero tenga en cuenta que la window
es un objeto global del contexto de JavaScript y no se crea a partir del prototype
. En otras palabras: no puede anularlo con window.prototype.postMessage = ...
Ejemplo con solución
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.'');
Cómo implementar esta solución
window.postMessage
función window.postMessage
en la parte de secuencia de comandos en su página HTML antes de la secuencia de comandos de Google Tag Manager. Pero de una mejor manera, podría ayudar a los desarrolladores de Google Tag Manager a comprender y corregir este error y puede esperar a que se corrija el script de Google Tag Manager.
Recientemente, recibí este mensaje de correo no se pudo clonar error. Está sucediendo en la mayoría de los últimos navegadores como Chrome 68, Firefox 61.0, IE11, Edge.
Error al ejecutar ''postMessage'' en ''Window'': la
function (a){if(qe.$a.hasOwnProperty(a))return qe.$a[a]}
no pudo clonarse.
La traza de pila es:
Error: Error al ejecutar ''postMessage'' en ''Window'':
function (a){if(qe.$a.hasOwnProperty(a))return qe.$a[a]}
no se pudo clonar.
en _reportEvent (eval at (: 1: 35637),: 94: 35)
en eval (eval at (: 1: 35637),: 55: 5)
en eval (eval at (: 1: 35637),: 433: 11)
Buscando en la fuente de mi página en DevTools muestra gtm.js
como la fuente del fragmento de código:
Tengo un código de seguimiento de Google Tag Manager en mi página. ¿Por qué está pasando esto?
Estos errores son causados por los rastreadores de Facebook que ejecutan el código JavaScript.
He tenido ocurrencias de este error en estas IP (todas en los rangos de IP de Facebook) y en los agentes de usuario:
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)
Para obtener una lista actualizada de las direcciones IP del rastreador de Facebook, vea este comando en https://developers.facebook.com/docs/sharing/webmasters/crawler/ :
whois -h whois.radb.net -- ''-i origin AS32934'' | grep ^route
Deberá actualizar su mecanismo de informe de errores para filtrar los errores de estos rangos de IP.
Puede hacer esto en el lado del cliente en JavaScript determinando la dirección IP del usuario en caso de error (consulte ¿Cómo obtener la dirección IP del cliente utilizando JavaScript? ).
O podrías hacer esto en el lado del servidor. Aquí hay un ejemplo para 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));
}
}