Running script tags fetched with jsonp

偶尔善良 提交于 2019-12-12 04:20:49

问题


Edit: Resolved, see answer below.

The problem I'm trying to solve is an ad loading script, that loads the ad code with jsonp and inserts it into the dom.

Now sometimes the ad code will include javascript tags, and from some posts here on stackoverflow i got the idea that moving them to head of the document to make them run, which after some experimentation prompted me to ask this question:

Appending scripts to head using javascript - weird behavior

My question there was solved but the problem remains, the scripts i insert into my test div does not run, nor do they run when moved to the head.

I have a code example here:

http://m.iijax.com/p1.html

And a simple jsonp example here:

http://m.iijax.com/p2.php

The code in p2 will try to log a message to the console, alert a message, and set a variable which i then try to print out, and all of these things fails.

Is the only way to run code like this using the eval function or am I doing some basic mistake?

Here is the code for the first part:

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
if (typeof JSONP === 'undefined') {
    /*Lightweight JSONP fetcher - www.nonobtrusive.com*/
    var JSONP = (function(){
        var counter = 0, head, query, key, window = this;
        function load(url) {
            var script = document.createElement('script'),
                done = false;
            script.src = url;
            script.async = true;

            script.onload = script.onreadystatechange = function() {
                if ( !done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") ) {
                    done = true;
                    script.onload = script.onreadystatechange = null;
                    if ( script && script.parentNode ) {
                        script.parentNode.removeChild( script );
                    }
                }
            };
            if ( !head ) {
                head = document.getElementsByTagName('head')[0];
            }
            head.appendChild( script );
        }
        function jsonp(url, params, callback) {
            query = "?";
            params = params || {};
            for ( key in params ) {
                if ( params.hasOwnProperty(key) ) {
                    query += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]) + "&";
                }
            }
            var jsonp = "json" + (++counter);
            window[ jsonp ] = function(data){
                callback(data);
                window[ jsonp ] = null;
                try {
                    delete window[ jsonp ];
                } catch (e) {}
            };

            load(url + query + "callback=" + jsonp);
            return jsonp;
        }
        return {
            get:jsonp
        };
    }());
}
JSONP.get( 'http://m.iijax.com/p2.php', { requestType:'demoRequest'}, function(data){
    var adC = document.getElementById("testId");
    adC.innerHTML = data.code;
    // Move script tags to head
    var scripts = adC.getElementsByTagName("script");
    for(i=scripts.length - 1;i>-1;i--) {
        document.head.appendChild(scripts[i]);
    }
    // Now check value of var letsSeeIfThisIsDefined, set in the fetched code
    console.log(letsSeeIfThisIsDefined);
});
</script>
</head>
<body>
    <div id="testId"></div>
</body>
</html>

回答1:


The answer seems a little bloated. Here's my version:

function execJSONP(url, cb) {
    var script = document.createElement('script');
    script.async = true;
    var callb = 'exec'+Math.floor((Math.random()*65535)+1);
    window[callb] = function(data) {
        var scr = document.getElementById(callb);
        scr.parentNode.removeChild(scr);
        cb(data);
        window[callb] = null;
        delete window[callb];
    }
    var sepchar = (url.indexOf('?') > -1)?'&':'?';
    script.src = url+sepchar+'callback='+callb;
    script.id = callb;
    document.getElementsByTagName('head')[0].appendChild(script);
}



回答2:


Thanks to this post:

Executing <script> elements inserted with .innerHTML

I was able to modify my code a little, I now pick out the data from the script tags fetched with jsonp, put it into newly created script tags and append them to the head and it works. :)

Here is the revised code, including the new function parseScripts():

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function parseScripts(elementId) {
    // Get the div where code has been inserted by innerHTML
    var td = document.getElementById(elementId);
    // Find any script tags in that code
    var scripts = td.getElementsByTagName("script");
    for(i=scripts.length - 1;i>-1;i--) {
        // For each script found pick out the data
        var elem = scripts[i];
        var data = (elem.text || elem.textContent || elem.innerHTML || "" );
        // Create a new script element and add the data
        var script = document.createElement("script");
        script.type = "text/javascript";
        try {
          // doesn't work on ie...
          script.appendChild(document.createTextNode(data));      
        } catch(e) {
          // IE has funky script nodes
          script.text = data;
        }
        // Append new script tag to head of document
        document.head.appendChild(script);
    }   
}

if (typeof JSONP === 'undefined') {
    /*Lightweight JSONP fetcher - www.nonobtrusive.com*/
    var JSONP = (function(){
        var counter = 0, head, query, key, window = this;
        function load(url) {
            var script = document.createElement('script'),
                done = false;
            script.src = url;
            script.async = true;

            script.onload = script.onreadystatechange = function() {
                if ( !done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") ) {
                    done = true;
                    script.onload = script.onreadystatechange = null;
                    if ( script && script.parentNode ) {
                        script.parentNode.removeChild( script );
                    }
                }
            };
            if ( !head ) {
                head = document.getElementsByTagName('head')[0];
            }
            head.appendChild( script );
        }
        function jsonp(url, params, callback) {
            query = "?";
            params = params || {};
            for ( key in params ) {
                if ( params.hasOwnProperty(key) ) {
                    query += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]) + "&";
                }
            }
            var jsonp = "json" + (++counter);
            window[ jsonp ] = function(data){
                callback(data);
                window[ jsonp ] = null;
                try {
                    delete window[ jsonp ];
                } catch (e) {}
            };

            load(url + query + "callback=" + jsonp);
            return jsonp;
        }
        return {
            get:jsonp
        };
    }());
}

JSONP.get( 'http://m.iijax.com/p2.php', { requestType:'demoRequest'}, function(data){
    var adC = document.getElementById("testId");
    adC.innerHTML = data.code;
    // Try and run the scripts
    parseScripts("testId");
});

</script>
</head>
<body>
    <div id="testId"></div>
    <div style="height: 0px; width: 0px; border: 10px solid transparent; border-left-color: #505050;"></div>
</body>
</html>


来源:https://stackoverflow.com/questions/6789502/running-script-tags-fetched-with-jsonp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!