jQuery的 - IFRAME访问被拒绝在IE浏览器上的某些页面(jquery - iframe

2019-07-19 22:05发布

我printThis的作者,一个jQuery插件进行打印。

https://github.com/jasonday/printThis

我已经提出了一个问题一个用户,我一直无法破解,不幸的是,我无法分享网页(隐私问题)。

在用户的网站,这个问题呈现在IE浏览一些网页,而不是其他。 打印失败的情况发生,因为IFRAME保持为空。

在IE中的错误是内jQuery的:

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

使用记录,我能确定它是围绕这条线出现故障:

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

但同样,这只是发生在某些页面,我一直无法任何实例重新创建该用户的站点之外。

我的问题:是否有更好的办法吗? 或方法,使$doc对象的详细防弹?


// -----------------------------------------------------------------------
// 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

问题由于document.domain

此类型的页已经document.domain设定和IE不继承document.domain从父。

为了解决这个问题部分,我改变的IFRAME创建到标准JavaScript和设置写入源document.domain上的iframe创建。

    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);

所以这个修复拒绝的访问,但现在的框架不能打印。 我已经尝试了很多的用于访问对象的不同方法,但他们都不工作。

A)你怎么会在这种情况下(我试过最多的方法概述了SO)访问帧获得IE浏览器识别并打印

要么

B)谁能想到一个更好的办法让document.domain的进入的iframe上创建与jQuery? (不能事后,为拒绝访问的问题上来了)

Answer 1:

在代码中,你正在使用setTimeout的iframe加载后执行的功能。

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

但是这是一个错误,因为你不知道,如果给出的时间是足以载入iframe或没有。 使用JavaScript异步的,没有保证setTimeout将抵消功能的执行,直到iframe的负荷。 由于加载时间是不同的页面不同。 有的不能正确执行代码,指向您发现的会导致错误的行。

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

正确的方法是使用事件loadonload结识如果DOM对象已正确或没有加载。

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


Answer 2:

只要你设置IFRAME SRC,同样的起源有对父元素进行验证,即使你把它设置为“关于:空白”。 我想在IE适当checkng失败,或者一些javascript运行并设置document.location比IFRAME创建不同的一个。

如何不设SRC都像下面这样? 它仍然应该工作。

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

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


Answer 3:

问题是由于IE浏览器不继承父document.domain的。

不幸的是,一旦你进入这个黑暗的区域,它采取了一些具体的黑客得到这个正常工作。

基本上做的,如果document.domain的被明确设置和浏览器是IE的支票。

全面更新的插件:

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);


Answer 4:

IE工程与像所有其他浏览器(至少为主要功能)的iframe。 你只需要保持一组规则:

  • 您加载在iframe(JS这需要了解的iframe父的那部分)任何JavaScript之前,确保父已document.domain的改变。
  • 当所有的iframe资源被加载,更改document.domain的是相同的,如亲本中定义的一个。 (您需要这样做,后来因为设置域将导致IFrame资源的请求失败)

  • 现在你可以为父窗口引用:var温= window.parent

  • 现在你可以让父HTML参考,以操纵它的:var parentContent = $(“HTML”,winn.document)
  • 在这一点上,你应该有机会获得IE父窗口/文件和你不会,你可以改变它


Answer 5:

这个答案已经在原来的问题UPDATE说,但我想一个更简洁的答案添加到与周围的SCRIPT70权限被拒绝的错误让原来的问题(我就遇到了这个在IE11 / Win7的使用jQuery 3.2.1)。

而不是$('<iframe .../>').appendTo($('body'))

做这个:

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

从这里取答案: https://bugs.jquery.com/ticket/13936#comment:28



文章来源: jquery - iframe access denied in IE on some pages