javascript - event - Problemas con Cross Document Messaging entre IFrame y Parent
postmessage javascript ejemplo (2)
El problema parece estar en tu PluginOnParent.js , donde estás enviando tu respuesta. En lugar de usar "e.origin" (que al inspeccionar las herramientas de desarrollador devolvía "nulo"), intente utilizar el literal "*", como se indica en la siguiente documentación sobre el uso de postMessage (en la descripción de targetOrigin ):
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
Además, como beneficio adicional, acabo de probar esto en dos dominios diferentes y funciona también. Coloqué Parent.html en un servidor web de dominios, y cambié el src del iframe para que fuera child.html en un dominio completamente diferente, y se comunicaron muy bien.
Parent.html
<html>
<head>
<script type="text/javascript">
function parentInitialize() {
window.addEventListener(''message'', function (e) {
// Check message origin etc...
if (e.data.type === ''iFrameRequest'') {
var obj = {
type: ''parentResponse'',
responseData: ''some response''
};
e.source.postMessage(obj, ''*'');
}
// ...
})
}
</script>
</head>
<body style="background-color: rgb(72, 222, 218);" onload="javascript: parentInitialize();">
<iframe src="child.html" style="width: 500px; height:350px;"></iframe>
</body>
</html>
Child.html
<html>
<head>
<script type="text/javascript">
function childInitialize() {
// ...
var timeoutId;
try {
if (window.self === window.top) {
// We''re not inside an IFrame, don''t do anything...
return;
}
} catch (e) {
// Browsers can block access to window.top due to same origin policy.
// See http://stackoverflow.com/a/326076
// If this happens, we are inside an IFrame...
}
function messageHandler(e) {
if (e.data && (e.data.type === ''parentResponse'')) {
window.clearTimeout(timeoutId);
window.removeEventListener(''message'', messageHandler);
// Do some stuff with the sent data
var obj = document.getElementById("status");
obj.value = e.data.responseData;
}
}
timeoutId = window.setTimeout(function () {
var obj = document.getElementById("status");
obj.value = ''Communication with parent page failed'';
window.removeEventListener(''message'', messageHandler);
}, 500);
window.addEventListener(''message'', messageHandler, false);
window.parent.postMessage({ type: ''iFrameRequest'' }, ''*'');
// ...
}
</script>
</head>
<body style="background-color: rgb(0, 148, 255);" onload="javascript: childInitialize();">
<textarea type="text" style="width:400px; height:250px;" id="status" />
</body>
</html>
¡Espero que ayude!
Tengo una aplicación ejecutándose dentro de un iframe en una página "extranjera" (dominio diferente, etc.). Para permitir alguna comunicación básica entre el iframe y el principal, postMessage
un script mío en la página principal y uso postMessage
para hacer algunos mensajes cruzados de documentos.
La mayoría de las veces esta comunicación funciona según lo previsto, pero a veces veo algunos errores informados en mi herramienta de seguimiento de errores y no puedo entender por qué ocurren.
Aquí hay un código ejemplar:
PluginOnParent.js
// ...
window.addEventListener(''message'', function(e) {
// Check message origin etc...
if (e.data.type === ''iFrameRequest'') {
e.source.postMessage({
type: ''parentResponse'',
responseData: someInterestingData
}, e.origin);
}
// ...
}, false);
// ...
AppInsideIFrame.js
// ...
var timeoutId;
try {
if (window.self === window.top) {
// We''re not inside an IFrame, don''t do anything...
return;
}
} catch (e) {
// Browsers can block access to window.top due to same origin policy.
// See http://stackoverflow.com/a/326076
// If this happens, we are inside an IFrame...
}
function messageHandler(e) {
if (e.data && (e.data.type === ''parentResponse'')) {
window.clearTimeout(timeoutId);
window.removeEventListener(''message'', messageHandler);
// Do some stuff with the sent data
}
}
timeoutId = window.setTimeout(function() {
errorTracking.report(''Communication with parent page failed'');
window.removeEventListener(''message'', messageHandler);
}, 500);
window.addEventListener(''message'', messageHandler, false);
window.parent.postMessage({ type: ''iFrameRequest'' }, ''*'');
// ...
¿Qué sucede aquí, cuando llega el tiempo de espera y se informa el error?
Más información y pensamientos míos:
- No tengo control sobre la página principal yo mismo
- No parece ser un problema general de "configuración" (CORS, etc.) ya que el error ocurre en la misma página donde funciona la mayor parte del tiempo.
- No admitimos IE <10 y otras versiones de navegadores "heredados", así que no hay problema aquí
- Mi herramienta de informe de errores informa de una multitud de navegadores diferentes, entre los que se encuentran las últimas versiones (FF 49, Chrome 43 en Android 5, Chrome 53 en Win y Android 6, Mobile Safari 10, ...)
- Por lo tanto, no parece ser un problema relacionado con navegadores o versiones específicos.
- El tiempo de espera de 500 ms es solo un número mágico que elegí, que pensé que sería completamente seguro ...
La mayoría de las veces esta comunicación funciona según lo previsto, pero a veces veo algunos errores informados en mi herramienta de seguimiento de errores y no puedo entender por qué ocurren.
¿Qué sucede aquí, cuando llega el tiempo de espera y se informa el error?
No tengo control sobre la página principal yo mismo
¿No está seguro de qué hace la función errorTracking.report
cuando se llama, aunque no parece que se produzca un error real relacionado con el evento del message
?
El tiempo de espera de 500 ms es solo un número mágico que elegí, que pensé que sería completamente seguro ...
Con la duration
establecida en 500
, podría llamarse a setTimeout
antes de que un evento de message
se active en la window
.
timeoutId = window.setTimeout(function() {
errorTracking.report(''Communication with parent page failed'');
window.removeEventListener(''message'', messageHandler);
}, 500);
Ajuste la duration
de setTimeout
a una duración mayor.
Alternativamente, sustituya el controlador window.addEventListener
o window.addEventListener
por setTimeout
Notas
Cuando se produce un error de sintaxis (?) En un script, cargado desde un origen diferente , los detalles del error de sintaxis no se informan para evitar la filtración de información (consulte el error 363897 ). En cambio, el error informado es simplemente "Error de script". Este comportamiento puede ser anulado en algunos navegadores usando el atributo crossorigin en y hacer que el servidor envíe los encabezados de respuesta HTTP
CORS
apropiados. Una solución alternativa es aislar "Error de script". y manejarlo sabiendo que los detalles del error solo se pueden ver en la consola del navegador y no se puede acceder a ellos a través de JavaScript.
Por ejemplo
// handle errors
onerror = function messageErrorHandlerAtAppInsideIFrame(e) {
console.error("Error at messageErrorIndex", e)
}
manejar cualquier error real durante la comunicación entre diferentes contextos u orígenes.
Use postMessage
en load
evento de load
de iframe
para comunicarse con los manejadores de message
en la window
principal.