it-swarm.com.de

jquery - iframe-Zugriff wurde verweigert IE auf einigen seiten

Ich bin der Autor von printThis, einem Jquery-Plugin zum Drucken.

https://github.com/jasonday/printThis

Ich habe einen Benutzer, der ein Problem angesprochen hat, das ich nicht knacken konnte, und leider kann ich die Seite nicht weitergeben (Datenschutzprobleme). 

Auf der Benutzerseite tritt das Problem auf einigen Seiten des IE auf, andere jedoch nicht. Der Druck wird nicht ausgeführt, da der iframe leer bleibt.

Der Fehler in IE liegt innerhalb von jQuery:

contents: function (a) {
            return f.nodeName(a,
                "iframe") ? a.contentDocument || a.contentWindow.document : f.makeArray(a.childNodes)
        }

Mit Hilfe der Protokollierung konnte ich feststellen, dass diese Zeile fehlschlug:

var $doc = $("#" + strFrameName).contents();

Dies geschieht jedoch nur auf einigen Seiten, und ich konnte in keinem Fall außerhalb der Site dieses Benutzers neu erstellen.

Meine Frage: Gibt es hier einen besseren Ansatz? oder eine Methode, um das $doc-Objekt kugelsicherer zu machen?


// -----------------------------------------------------------------------
// printThis v1.1
// Printing plug-in for jQuery
//
// Resources (based on) :
//              jPrintArea: http://plugins.jquery.com/project/jPrintArea
//              jqPrint: https://github.com/permanenttourist/jquery.jqprint
//              Ben Nadal: http://www.bennadel.com/blog/1591-Ask-Ben-Print-Part-Of-A-Web-Page-With-jQuery.htm
//
// Dual licensed under the MIT and GPL licenses:
//              http://www.opensource.org/licenses/mit-license.php
//              http://www.gnu.org/licenses/gpl.html
//
// (c) Jason Day 2012
//
// Usage:
//
// $("#mySelector").printThis({
//      debug: false, //show the iframe for debugging
//      importCSS: true, // import page CSS
//      printContainer: true, // grab outer container as well as the contents of the selector
//      loadCSS: "path/to/my.css" //path to additional css file
//  });
//
// Notes:
//  - the loadCSS option does not need @media print
//------------------------------------------------------------------------

(function($) {
    var opt;

    $.fn.printThis = function (options) {
        opt = $.extend({}, $.fn.printThis.defaults, options);

        var $element = (this instanceof jQuery) ? this : $(this);

    // if Opera, open a new tab
        if ($.browser.opera)
        {
            var tab = window.open("","Print Preview");
            tab.document.open();


        }
    // add dynamic iframe to DOM
        else
        {
        var strFrameName = ("printThis-" + (new Date()).getTime());

            var $iframe = $("<iframe id='" + strFrameName +"' src='about:blank'/>");

            if (!opt.debug) { $iframe.css({ position: "absolute", width: "0px", height: "0px", left: "-600px", top: "-600px" }); }

            $iframe.appendTo("body");

        }
    // allow iframe to fully render before action
    setTimeout ( function () {

        if ($.browser.opera)
            {
        var $doc = tab.document;
        } else
        {
        var $doc = $("#" + strFrameName).contents();
        }



        // import page css
        if (opt.importCSS)
        {
                $("link[rel=stylesheet]").each(function(){
                var href = $(this).attr('href');
                if(href){
                        var media = $(this).attr('media') || 'all';
                        $doc.find("head").append("<link type='text/css' rel='stylesheet' href='" + href + "' media='"+media+"'>");
                    }
        });
        }

        // add another stylesheet
        if (opt.loadCSS)
        {
        $doc.find("head").append("<link type='text/css' rel='stylesheet' href='" + opt.loadCSS + "'>");

        }

        //add title of the page
        if (opt.titlePage)
        {
        $doc.find("head").append('<title>'+opt.titlePage+'</title>');
        } 
        //grab outer container
        if (opt.printContainer) { $doc.find("body").append($element.outer()); }
        else { $element.each( function() { $doc.find("body").append($(this).html()); }); }

        //$doc.close();
        // print
        ($.browser.opera ? tab : $iframe[0].contentWindow).focus();
        setTimeout( function() { ($.browser.opera ? tab : $iframe[0].contentWindow).print(); if (tab) { tab.close(); } }, 1000);

        //removed iframe after 60 seconds
        setTimeout(
        function(){
        $iframe.remove();
        },
        (60 * 1000)
        );
    }, 333 );
    }


    $.fn.printThis.defaults = {
        debug: false, //show the iframe for debugging
        importCSS: true, // import page CSS
        printContainer: true, // grab outer container as well as the contents of the selector
        loadCSS: "", //path to additional css file
        titlePage: "" //add title to print page
    };


    jQuery.fn.outer = function() {
      return $($('<div></div>').html(this.clone())).html();
    }
})(jQuery);

UPDATE

Ausgabe an wegen document.domain

Dieser Seitentyp hat document.domain gesetzt und IE erbt document.domain nicht vom übergeordneten Element. 

Um diesen Teil zu korrigieren, habe ich die Erstellung von Iframes in Standard-Javascript geändert und die Quelle so gesetzt, dass document.domain bei der Iframe-Erstellung geschrieben wird.

    var printI= document.createElement('iframe');

    printI.name = "printIframe";

    printI.id = strFrameName;

    document.body.appendChild(printI);

    printI.src = "javascript:document.write('<head><script>document.domain=\"mydomain.com\";</script></head><body></body>')";


   var $iframe = $("#" + strFrameName);

Dadurch wird der Zugriff verweigert, jedoch wird der Rahmen jetzt nicht gedruckt. Ich habe viele verschiedene Methoden ausprobiert, um auf das Objekt zuzugreifen, aber keine davon funktioniert.

A) Wie würden Sie in diesem Szenario auf den Frame zugreifen (ich habe die meisten der auf SO beschriebenen Methoden versucht), um IE zum Erkennen und Drucken zu bringen

oder

B) kann sich jemand einen besseren Weg vorstellen, die document.domain bei der Erstellung mit jQuery in den iframe zu bringen? (kann nicht danach sein, da der Zugriff verweigert wird)

12
Jason

Das Problem liegt daran, dass IE die übergeordnete document.domain nicht erbt.

Sobald Sie sich in diesem düsteren Bereich befanden, waren leider einige Hacks erforderlich, damit dies ordnungsgemäß funktioniert. 

Grundsätzlich wird geprüft, ob document.domain explizit gesetzt wird und der Browser IE ist. 

Vollständig aktualisiertes Plugin:

https://github.com/jasonday/printThis

(function ($) {
    var opt;
    $.fn.printThis = function (options) {
        opt = $.extend({}, $.fn.printThis.defaults, options);
        var $element = this instanceof jQuery ? this : $(this);

            var strFrameName = "printThis-" + (new Date()).getTime();

            if(window.location.hostname !== document.domain && navigator.userAgent.match(/msie/i)){
                // Ugly IE hacks due to IE not inheriting document.domain from parent
                // checks if document.domain is set by comparing the Host name against document.domain
                var iframeSrc = "javascript:document.write(\"<head><script>document.domain=\\\"" + document.domain + "\\\";</script></head><body></body>\")";
                var printI= document.createElement('iframe');
                printI.name = "printIframe";
                printI.id = strFrameName;
                printI.className = "MSIE";
                document.body.appendChild(printI);
                printI.src = iframeSrc;

            } else {
                 // other browsers inherit document.domain, and IE works if document.domain is not explicitly set
                var $frame = $("<iframe id='" + strFrameName +"' name='printIframe' />");
                $frame.appendTo("body");
            }


            var $iframe = $("#" + strFrameName);

            // show frame if in debug mode
            if (!opt.debug) $iframe.css({
                position: "absolute",
                width: "0px",
                height: "0px",
                left: "-600px",
                top: "-600px"
            });


        // $iframe.ready() and $iframe.load were inconsistent between browsers    
        setTimeout ( function () {

            var $doc = $iframe.contents();

            // import page stylesheets
            if (opt.importCSS) $("link[rel=stylesheet]").each(function () {
                var href = $(this).attr("href");
                if (href) {
                    var media = $(this).attr("media") || "all";
                    $doc.find("head").append("<link type='text/css' rel='stylesheet' href='" + href + "' media='" + media + "'>")
                }
            });

            //add title to iframe
            if (opt.pageTitle) $doc.find("head").append("<title>" + opt.pageTitle + "</title>");

            // import additional stylesheet
            if (opt.loadCSS) $doc.find("head").append("<link type='text/css' rel='stylesheet' href='" + opt.loadCSS + "'>");

            // grab $.selector as container
            if (opt.printContainer) $doc.find("body").append($element.outer());

            // otherwise just print interior elements of container
            else $element.each(function () {
                $doc.find("body").append($(this).html())
            });

            if($iframe.hasClass("MSIE")){
                // check if the iframe was created with the ugly hack
                // and perform another ugly hack out of neccessity
                window.frames["printIframe"].focus();
                setTimeout(function () {
                   $doc.find("head").append("<script>  window.print(); </script>");
                }, 500 );
            } else {
                // proper method
                $iframe[0].contentWindow.focus();
                $iframe[0].contentWindow.print();  
            }

             //remove iframe after print
            if (!opt.debug) {
                setTimeout(function () {
                    $iframe.remove();
                }, 1000);
            }


        }, 333 );

    };

    // defaults
    $.fn.printThis.defaults = {
        debug: false,           // show the iframe for debugging
        importCSS: true,        // import parent page css
        printContainer: true,   // print outer container/$.selector
        loadCSS: "",            // load an additional css file
        pageTitle: ""           // add title to print page
    };

    // $.selector container
    jQuery.fn.outer = function () {
        return $($("<div></div>").html(this.clone())).html()
    }
})(jQuery);
4
Jason

In Ihrem Code verwenden Sie setTimeout, um Ihre Funktion auszuführen, nachdem der Iframe geladen wurde.

// allow iframe to fully render before action
setTimeout ( function () {
...
}, 333 );  //333ms

dies ist jedoch ein Fehler, da Sie nicht wissen, ob die angegebene Zeit zum Laden des Iframes ausreicht oder nicht. Die Ausführung von Javascript ist asynchron. Es kann also nicht garantiert werden, dass setTimeout die Ausführung der Funktion bis zum Laden von iframe ausgleicht. Da die Ladezeit für verschiedene Seiten unterschiedlich ist. Einige können den Code nicht richtig ausführen und zeigen auf die Zeile, die Fehler verursacht. 

var $doc = $("#" + strFrameName).contents();  //only after loading

Der richtige Weg ist, das Ereignis load oder onload zu verwenden, um herauszufinden, ob das DOM-Objekt ordnungsgemäß geladen wurde oder nicht.

<script>
document.getElementById("myframe").onload = function() {
  alert("myframe is loaded");
};
</script>
//or
<iframe id="myFrame" onload="myFunction();"></iframe>
6
user568109

Solange Sie iframe src festlegen, muss derselbe Ursprung mit dem übergeordneten Element verifiziert werden, auch wenn Sie ihn als 'about: blank' festlegen. Ich schätze, IE schlägt in der richtigen Prüfung fehl, oder es wurde ein Javascript ausgeführt und der document.location auf einen anderen Wert gesetzt, als der Iframe erstellt wird.

Wie wäre es, wenn Sie src NICHT wie folgt einstellen? es sollte noch funktionieren.

var $iframe = $("<iframe id='" + strFrameName +"'/>");
$iframe.appendTo("body");
var $iframeDoc = $iframe[0].contentWindow.document;

$iframeDoc.open();
$iframeDoc.write("foo");
$iframeDoc.close();
5
allenhwkim

Diese Antwort wurde bereits in der ursprünglichen Frage UPDATE angegeben, aber ich wollte der ursprünglichen Frage, die mit dem Umgehen des SCRIPT70-Zugriffsrechtsschutzes zu tun hatte, eine knappere Antwort geben (ich habe dies mit IE11/Win7 mit JQuery 3.2.1 festgestellt).

Anstelle von $('<iframe .../>').appendTo($('body'))

Mach das: 

var $iframe = $('<iframe .../>');
document.body.appendChild($iframe[0]);

Antwort von hier genommen: https://bugs.jquery.com/ticket/13936#comment:28

0
splashout

IE arbeitet mit iframe wie alle anderen Browser (zumindest für Hauptfunktionen). Sie müssen nur eine Reihe von Regeln einhalten:

  • bevor Sie Javascript in den iframe laden (den Teil von js, der über den übergeordneten iframe-übergeordneten Server informiert werden muss), stellen Sie sicher, dass der übergeordnete Abschnitt document.domain geändert wurde.
  • wenn alle iFrame-Ressourcen geladen sind, ändern Sie document.domain so, dass sie der im übergeordneten Element definierten entspricht. (Sie müssen dies später tun, da das Festlegen der Domäne dazu führt, dass die Anforderung der iFrame-Ressource fehlschlägt.)

  • jetzt können Sie eine Referenz für das übergeordnete Fenster erstellen: var winn = window.parent

  • jetzt können Sie einen Verweis auf übergeordnetes HTML erstellen, um ihn zu bearbeiten: var parentContent = $ ('html', winn.document)
  • an diesem Punkt sollten Sie Zugriff auf IE übergeordnetes Fenster/Dokument haben und Sie können es nach Belieben ändern
0
Ionut Tocila