最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Cant access JS function in Cross Domain Environment - Stack Overflow

programmeradmin3浏览0评论

In order to solve Cross Domain security woes of JavaScript, I am implementing the following method

On Domain [ abc ]

On domain abc I have a page called main_page.html. Its code is as follows -

<script>
function SendMsg(id)
{
   frames["invisible_iframe"].location = ".html#"+id;
}
</script>
<body>
  <input type="button" id="Test" value="Call iFrame" onclick="SendMsg(this.id);">
  <iframe src="ttp://xyz/visible_iframe.html" name="visible_iframe" height="250" width="500"></iframe>
  <iframe name="invisible_iframe" height="0" width="0" style="display:none;"></iframe>
</body>

On Domain [ xyz ]

On domain xyz I have a page called visible_iframe.html. Its code is as follows -

<script>
function Hi()
{
   alert("Hi there!");
}
</script>
<body>
  <h1>Visible iFrame on xyz
  <iframe name="d2_invisible_iframe" id="d2_invisible_iframe" class="iFrame" src=".html" height="310" width="520"></iframe>
</body>

Now I want to access the function Hi() from invisible_iframe.html (which is on the same domain)

The code of invisible_iframe.html is as follows

<script>
var sActionText = "";
function CheckForMessages()
{
   if(location.hash != sActionText)
   {
     sActionText = location.hash;
     var sAction = "";
     var oSplitActionText = sActionText.split("#");
     sAction = oSplitActionText[1];
     if (sAction == "Test")
     {
        parent.Hi();
     }
   }
}

setInterval(CheckForMessages, 200); 
</script>
<body>
  <h1>Invisible iFrame on xyz</h1>
</body>

I am using hidden iFrame in visible_iframe.html because I don't want the URL of visible_iframe.html to change.

Now I expect when the button on main_page.html is clicked, I'd get alert message. But that doesn't happen. In firefox it says - Permission denied to access property 'Hi'

The strange thing is when I put parent.Hi(); outside CheckForMessages() function, the Hi() function can be accessed and alert box is shown.

What should I do to resolve this ?

In order to solve Cross Domain security woes of JavaScript, I am implementing the following method

On Domain [ abc. ]

On domain abc. I have a page called main_page.html. Its code is as follows -

<script>
function SendMsg(id)
{
   frames["invisible_iframe"].location = "http://xyz./invisible_iframe.html#"+id;
}
</script>
<body>
  <input type="button" id="Test" value="Call iFrame" onclick="SendMsg(this.id);">
  <iframe src="ttp://xyz./visible_iframe.html" name="visible_iframe" height="250" width="500"></iframe>
  <iframe name="invisible_iframe" height="0" width="0" style="display:none;"></iframe>
</body>

On Domain [ xyz. ]

On domain xyz. I have a page called visible_iframe.html. Its code is as follows -

<script>
function Hi()
{
   alert("Hi there!");
}
</script>
<body>
  <h1>Visible iFrame on xyz.
  <iframe name="d2_invisible_iframe" id="d2_invisible_iframe" class="iFrame" src="http://xyz./invisible_iframe.html" height="310" width="520"></iframe>
</body>

Now I want to access the function Hi() from invisible_iframe.html (which is on the same domain)

The code of invisible_iframe.html is as follows

<script>
var sActionText = "";
function CheckForMessages()
{
   if(location.hash != sActionText)
   {
     sActionText = location.hash;
     var sAction = "";
     var oSplitActionText = sActionText.split("#");
     sAction = oSplitActionText[1];
     if (sAction == "Test")
     {
        parent.Hi();
     }
   }
}

setInterval(CheckForMessages, 200); 
</script>
<body>
  <h1>Invisible iFrame on xyz.</h1>
</body>

I am using hidden iFrame in visible_iframe.html because I don't want the URL of visible_iframe.html to change.

Now I expect when the button on main_page.html is clicked, I'd get alert message. But that doesn't happen. In firefox it says - Permission denied to access property 'Hi'

The strange thing is when I put parent.Hi(); outside CheckForMessages() function, the Hi() function can be accessed and alert box is shown.

What should I do to resolve this ?

Share Improve this question edited Jun 11, 2012 at 6:03 skos asked Jun 7, 2012 at 8:25 skosskos 4,2228 gold badges38 silver badges59 bronze badges 4
  • If Stock Overflow's answer below, didn't help you, what exactly do you expect from this? your Hi function is not at the invisible_iframe's parent's domain, it's inside one if its iframes! so clarify here. maybe I can help you on that. – Sepehr Commented Jun 9, 2012 at 19:01
  • There was a little confusion in my question. I have edited it now. Extremely sorry for the inconvenience. – skos Commented Jun 11, 2012 at 5:43
  • @Sachyn, do you have the ability to edit/create html files on both domains (abc. + xyz.)? – Jacob Swartwood Commented Jun 12, 2012 at 20:32
  • @ActionJake Yes I can make changes on both domains, provided changes aren't too frequent – skos Commented Jun 13, 2012 at 5:19
Add a ment  | 

9 Answers 9

Reset to default 4 +200

Why not using easyXDM? This library should make your life really easy and help to avoid the security limitations when dealling with cross domain issues. Specially if you have control over the two domains.

easyXDM is a Javascript library that enables you as a developer to easily work around the limitation set in place by the Same Origin Policy, in turn making it easy to municate and expose javascript API’s across domain boundaries.

[This is one of the best and easy to use APIs] available for Cross Domain Communication between web applications. easyXDM is easy to use, light weight, flexible, writing good quality code etc. I strongly think if you are going to continue with cross domain scenario, then you should adapt a robust cross domain apis such as easyXDM.

[easyXDM vs PostMessage Transport?] easyXDM will use the PostMessageTransport method if this feature is enabled by the browser such as (IE8+, Opera 9+, Firefox 3+, Safari 4+,Chrome 2+) on the other side it will use different transport methods for the un supported browsers such as (Firefox 1-2 - using the FrameElementTransport) other transport methods will be used as needed such as FlashTransport, NameTransport, and HashTransport).

This clearly makes easyXDM superior in terms on browser support specially the old browsers.


To demonstrate cross-domain access using easyXDM (Domain1 [abc.] calls a method on a remote domain [xyz.]):


*On Domain [ abc. ] - main domain*

    <script type="text/javascript">
        /**
         * Request the use of the JSON object
         */
        easyXDM.DomHelper.requiresJSON("../json2.js");
    </script>
    <script type="text/javascript">
        var remote;
        window.onload = function(){
            /**
             * When the window is finished loading start setting up the interface
             */
            remote = new easyXDM.Interface(/** The channel configuration */{
                /**
                 * Register the url to hash.html, this must be an absolute path
                 * or a path relative to the root.
                 * @field
                 */
                local: "/hash.html",
                /**
                 * Register the url to the remote interface
                 * @field
                 */
                remote: "http://YOUR.OTHER.DOMAIN/YOUR_APPLICATION/YourRemoteApplication.html",
                /**
                 * Register the DOMElement that the generated IFrame should be inserted into
                 */
                container: document.getElementById("embedded")
            }, /** The interface configuration */ {
                remote: {
                    remoteApplicationMethod: {},
                    noOp: {
                        isVoid: true
                    }
                },
                local: {
                    alertMessage: {
                        method: function(msg){
                            alert(msg);
                        },
                        isVoid: true
                    }
                }
            },/**The onReady handler*/ function(){
                /**
                 * Call a method on the other side
                 */
                remote.noOp();
            });
        }

        function callRemoteApplicationMethod(Value1, Value2){
            remote.remoteApplicationMethod(Value1, Value2, function(result){
                alert("Results from remote application" + result);
            });
        }


    </script>

In the body

<input type="button" onclick="callRemoteApplicationMethod(3,5)" value="call remoteApplicationMethod on remote domain"/>

Now on your remote domain side you need to define your remote client as follows

*On Domain [ xyz. ] - Remote domain*

This should go into the page YOUR_APPLICATION/YourRemoteApplication.html

    <script type="text/javascript">
        /**
         * Request the use of the JSON object
         */
        easyXDM.DomHelper.requiresJSON("../json2.js");
    </script>
    <script type="text/javascript">
        var channel, remote;
        /**
         * When the window is finished loading start setting up the channel
         */
        window.onload = function(){

            /**
             * When the channel is ready we create the interface
             */
            remote = new easyXDM.Interface(/** The channel configuration*/{}, /** The configuration */ {
                remote: {
                    alertMessage: {
                        isVoid: true
                    }
                },
                local: {
                    remoteApplicationMethod: {
                        method: doSomething(value1, value2){
                        // do somethigs with values

                        return "i'm return value from remote domain";
                        }
                    },
                    noOp: {
                        isVoid: true,
                        method: function(){
                            alert("Method not returning any data");
                        }
                    }
                }
            });
        }
    </script>

I suppose there is no need to suport old browsers, right? You can use window.postMessage in modern browsers to support cross-origin munication.

You won't believe the cause. On main_page.html (abc.) you define two iframes but you don't close them (missing </iframe>). Now there are two cases:

Case 1:

iframes are independent so your main_page.html code should be

<iframe src="http://xyz./visible_iframe.html" ...></iframe>
<iframe src="http://xyz./invisible_iframe.html" ...></iframe>

and the javascript call from invisible_iframe.html should be

parent.frames["visible_iframe"].Hi();

Case 2:

iframes are parent and child so main_page.html code should be

<iframe src="http://xyz./visible_iframe.html" ...></iframe>

visible_iframe.html code sould include

<iframe src="http://xyz./invisible_iframe.html" ...></iframe>

and the javascript call from invisible_iframe.html should be

parent.Hi();

That's all. The choice is yours.

Assuming your onlcick works on your input (just a typo there): from invisible_frame, you should address visible_frame's Hi() with parent.frames['visible_frame'].Hi().

For now, parent.Hi() tries to access a Hi() located on abc.'s page (as it is the frame's parent), so you're poked with the hard stick of Same Origin Policy.

Hope this helps and works ;)

Try creating these three files:

http://abc./main.html:

<!DOCTYPE html>
<html>
<head>
    <script>
    function SendMsg(id) {
        window.frames.invisible.location = 'http://xyz./invisible.html#' + id;
    }
    </script>
</head>
<body>
    <input type="button" id="Test" value="Call iFrame" onclick="SendMsg(this.id);">
    <iframe src="http://xyz./visible.html" name="visible" height="250" width="500"></iframe>
    <iframe name="invisible" height="0" width="0" style="display:none;"></iframe>
</body>
</html>

http://xyz./visible.html:

<!DOCTYPE html>
<html>
<head>
    <script>
    function Hi() {
        alert('Hi there!');
    }
    </script>
</head>
<body>
    <h1>Visible on xyz.</h1>
</body>
</html>

http://xyz./invisible.html:

<!DOCTYPE html>
<html>
<head>
    <script>
    var sActionText = "";
    function CheckForMessages() {
        if (location.hash != sActionText) {
            sActionText = location.hash;
            var sAction = "";
            var oSplitActionText = sActionText.split("#");
            sAction = oSplitActionText[1];
            if (sAction == "Test") {
                parent.frames.visible.Hi();
            }
        }
    }
    setInterval(CheckForMessages, 200); 
    </script>
</head>
<body>
    <h1>Invisible on xyz.</h1>
</body>
</html>

Notice that the frame structure is:

       main
       /  \
      /    \
visible    invisible

And so if you need to access visible from invisible, you need to go:

parent.frames.visible.Hi()

Moving forward, I suggest using easyXDM or the jQuery postMessage plugin for cross-domain munication instead of reinventing the wheel.

There is a reason it is not letting you access the function because of the same origin policy. It would cause real security issues if you could.

CORS (Cross-Origin Resource Sharing) or window.postMessage (ref: Docs on MDN or another simple postMessage example) are definitely worth investigating if you don't care about IE7 support; you could also use a postMessage shim for older IE browsers.

However, I'll stick with an iframe solution in an attempt to more precisely answer your question.

Unfortunately you should not be able to access the parent (window scope) properties/methods from a cross domain iframe. However you can access window scopes via iframes on the same domain ...at any depth. Thus, one solution is to leverage vertical iframe tunnels.

If you create three html documents:

Top level - abc.

<script>
    function sendMsg( id ) {
       frames["invisible_iframe"].location = "//xyz./mid_level.html#" + id;
    }

    window.ACTIONS = {
        Test: function() {
            alert("hello");
            // This action could also start an interaction with another
            // visible iframe by setting a hash, etc
        }
    };
</script>
<input type="button" id="Test" value="Call iFrame" onclick="sendMsg(this.id);">
<iframe name="invisible_iframe" height="0" width="0" frameborder="0" style="visibility:hidden;" src="//xyz./mid_level.html"></iframe>

Mid Level - xyz.

<script>
    function sendMsg( id ) {
       frames["invisible_iframe"].location = "//abc./low_level.html#" + id;
    }

    var sActionText = "";
    function checkForMessages() {
       if(location.hash != sActionText) {
         sActionText = location.hash.replace(/^#/, "");
         location.hash = "";

         sendMsg(sActionText);
       }
    }

    setInterval(checkForMessages, 20); 
</script>
<iframe name="invisible_iframe" height="0" width="0" frameborder="0" style="visibility:hidden;" src="//abc./low_level.html"></iframe>

Low Level - abc.

<script>
    function runActionInTop( action ) {
        try {
            window.top.ACTIONS[action]();
        } catch ( err ) {
            // Bad action!
        }
    }

    var sActionText = "";
    function checkForMessages() {
       if(location.hash != sActionText) {
         sActionText = location.hash.replace(/^#/, "");
         location.hash = "";

         runActionInTop(sActionText);
       }
    }

    setInterval(checkForMessages, 20); 
</script>

These three iframes can municate - the first and third can municate directly and the second indirectly (via hash in this example).

I know this is a variation from what you were originally trying to show with the "visible iframe". I wanted to focus on illustrating the layering necessary for the cross-site munication. If you still need the visible iframe, you could add munication hooks at the top level and also send additional information (in the hash) back from the middle frame to the lowest frame (the lowest frame could then municate the information directly back to the top page).

Yes, I know this is convoluted - that is one of the reasons why CORS and postMessage exist :)

I've also changed a few minor aspects of your original code that I think are worth pointing out:

  • Using // instead of http:// means that this system will work on either http or https.
  • Some browsers (I believe I first ran into this with Safari 3) may not actually load the iframe with display:none; setting the frameborder attribute and visibility:hidden will keep the iframe from being visible.
  • Some browsers will load about:blank (or a similar page) if you do not specify the iframe src attribute in the markup. On https pages, this can cause insecure content warnings to be thrown in IE.

An alternative, Proxying.

In server-side grab the external file and echo it back. Now it is on your domain so no issues.

for example in php

<?php
  $external-site = file_get_contents('http://xyz./');
  echo $external-site;
?>

I think I would delete any iframes and use jsonp maybe with a library. 1. No Cross-domain errors 2. You could get data as objects (easy to play with 'em 3. You could even get JS code that u could parse. 4. Would be even mobile ready ( iframes are last century solutions... ) But then well maybe you are not able to take away the iframes for any reasons, so I advice to use a ready-made library solution. Goodluck

发布评论

评论列表(0)

  1. 暂无评论