Cross domain iframe events

Front-end HTML

Wie zegt dat cross domain iframe events en function calls niet mogelijk zijn? postMessage is hier de oplossing.

Het probleem: cross-domain security

Stel we hebben een html pagina met daarin een iframe en een javascript functie:

html
<!DOCTYPE html>
<html>
<head></head>
<body>
    <iframe src="http://iframe-source" frameborder="0"></iframe>
    <script>
        var functionInParent = function () {
            alert('functionInParent is called');
        };
    </script>
</body>
</html>

En een iframe source pagina op een ander domein die de functie in zijn parent aanroept:

html
<!DOCTYPE html>
<html>
<head></head>
<body>
    <script>
        parent.functionInParent();
    </script>
</body>
</html>

Bij het laden van de iframe source zal parent.functionInParent aangeroepen worden. Als zowel de parent als de iframe source zich op hetzelfde domein zouden bevinden, gaat alles goed. Maar als de iframe source zich op een ander domein bevindt, is er sprake van cross-domain communicatie. Dit resulteert in een security error:
Uncaught SecurityError: Blocked a frame with origin “http://cross-domain.com” from accessing a frame with origin “http://current-domain.com”. Protocols, domains, and ports must match.

Oplossing: postMessage

Met postMessage kan een message event worden getriggerd, waarbij een target kan worden meegegeven. De target is het domein waarop zich de parent pagina met de event listener bevindt.

Eerder genoemd code voorbeeld met het cross-domain security issue kan met postMessage worden opgelost met voor de parent pagina:

html
<!DOCTYPE html>
<html>
<head></head>
<body>
    <iframe src="http://iframe-source" frameborder="0"></iframe>
    <script>
        var functionInParent = function () {
            alert('functionInParent is called');
        };
 
        window.addEventListener("message",function (ev) {
            if (ev.data === "I'd like to invoke functionInParent") {
                functionInParent();
            }
        }, false);
    </script>
</body>
</html>

De parent pagina is nu uitgebreid met een event listener voor het ‘message’ event. De callback functie van de event listener checkt een conditie en voert dan de functionInParent uit.

html
<!DOCTYPE html>
<html>
<head></head>
<body>
    <script>
        var targetDomain = '*';
        var targetWindow = window.parent;
 
        targetWindow.postMessage("I'd like to invoke functionInParent", targetDomain);
    </script>
</body>
</html>

De functionInParent call in de iframe source pagina is vervangen door een postMessage call. Deze functie wordt aangeroepen op het parent object. De functie bevat een parameter voor het target domain. Daar staat het domein van de parent waarin het iframe wordt getoond.

In het voorbeeld is voor het targetDomain een ‘*’ gedefinieerd. Dit zorgt ervoor dat niet alleen elk domein, maar ook elk protocol het ‘message’ event kan listenen. Dit is erg handig voor bijvoorbeeld een Cordova applicatie die draait op file://, i.p.v. http://

Front-end HTML