检测浏览器是不是支持带有 iframe 的数据 uri 方案

Posted

技术标签:

【中文标题】检测浏览器是不是支持带有 iframe 的数据 uri 方案【英文标题】:Detect if browser supports data uri scheme with iframes检测浏览器是否支持带有 iframe 的数据 uri 方案 【发布时间】:2014-09-27 04:48:24 【问题描述】:

Internet Explorer 不支持 iframe url 的数据 uri 方案(请参阅http://msdn.microsoft.com/en-us/library/cc848897%28v=vs.85%29.aspx)。其他浏览器可以。由于浏览器检测包含测试和面向未来的问题,我想使用功能检测来解决这个问题。

那么:如何检测浏览器是否支持 iframe 的数据 uri 方案?

【问题讨论】:

来自modernizr 的线程在谈论它,看起来他们还没有解决方案。 github.com/Modernizr/Modernizr/issues/1190 从 data-uri 加载的框架文档是跨站点来源的,因此访问框架文档会引发安全违规。如果您从没有 src 属性(或 src="about:blank")开始并将加载事件附加到框架,则 this.contentWindow.document 将成功抛出。即使没有加载任何内容,IE 也会触发 load 事件,因此只需简单的 try/catch 即可告诉您浏览器是否支持框架中的数据 uri。 【参考方案1】:

如果带有data: URI 的iframeonload 事件触发,则浏览器支持data: URI。否则,浏览器不支持data: URI。

示例代码还通过从iframe 向父窗口发送消息来检查是否允许从data: URI 编写脚本。

工作代码

var iframeDataURISupport =  checked: false, supported: false, scriptingSupported: false ;

function iframesSupportDataURIs(callback) 
    if (!iframeDataURISupport.checked) 
        var iframe = document.createElement('iframe'), alreadyCalled = false, done = function () 
            if (!alreadyCalled) 
                alreadyCalled = true;

                document.body.removeChild(iframe);

                console.log(iframeDataURISupport);

                callback && callback(iframeDataURISupport);
            
        , previousMessageHandler = window.onmessage, dataURI = 'data:text/html,<' + 'script>window.parent.postMessage("data: URIs supported", "*");<' + '/script>';

        window.onmessage = function (e) 
            if (e.data === 'data: URIs supported') 
                window.onmessage = previousMessageHandler;

                iframeDataURISupport.supported = true;
                iframeDataURISupport.scriptingSupported = true;

                done();
             else 
                window.onmessage.apply(this, arguments);
            
        ;

        iframe.src = dataURI;
        iframe.setAttribute('style', 'display: inline-block; width: 0; height: 0; overflow: hidden; border: 0 none; padding: 0; margin: 0;'.replace(/;/g, ' !important;'));

        iframe.onload = function (e) 
            if (iframe.src === dataURI) 
                iframeDataURISupport.supported = true;

                setTimeout(done, 100);
             else done();
        ;

        document.body.appendChild(iframe);

        setTimeout(done, 500);
     else 
        setTimeout(function () 
            callback && callback(iframeDataURISupport);
        , 5);
    
;

用法

iframesSupportDataURIs(function (details) 
    alert('This browser ' + (details.supported ? 'supports' : 'does not support') + ' data: URIs. It ' + (details.scriptingSupported ? 'also supports' : 'does not support') + ' scripting from data: URIs');
);

如果你想要更高级的控制,你可以这样称呼它:

iframeDataURISupport.checked ? functionName(iframeDataURISupport) : iframesSupportDataURIs(functionName);

演示

Play with it on JSFiddle.

【讨论】:

谢谢@toothbrush,但是用IE(11)测试小提琴,脚本告诉我支持数据URI和来自数据URI的脚本,不幸的是事实并非如此。在任何情况下都会触发 onload 事件。 @PaulTaylor 我认为它现在应该可以工作了,我已经更新了帖子。我目前无法访问运行 Internet Explorer 11 的机器,但也许您可以告诉我它现在是否可以工作? IE 现在说“支持数据 url,不支持脚本”——越来越近了!【参考方案2】:

This solution by Kevin Martin 已经过测试,似乎在 IE、FF 和 Chrome 中给出了正确的结果:

function iframeDataURITest(src) 
    var support,
        iframe = document.createElement('iframe');

    iframe.style.display = 'none';
    iframe.setAttribute('src', src);

    document.body.appendChild(iframe);

    try 
        support = !!iframe.contentDocument;
     catch (e) 
        support = false;
    

    document.body.removeChild(iframe);

    return support;


console.log('Empty data uri', iframeDataURITest('data:;base64,'));
console.log('"*" data uri', iframeDataURITest('data:text/html;base64,Kg=='));

与其他一些建议不同,它是同步的 - 无需处理超时或回调。

【讨论】:

以上是关于检测浏览器是不是支持带有 iframe 的数据 uri 方案的主要内容,如果未能解决你的问题,请参考以下文章

检测此页面是不是在跨域 iframe 内部的万无一失的方法

当浏览器请求部分内容范围请求时,如何检测何时在 iframe 中加载 pdf?

检测 iframe 加载错误

检测 iframe src 是不是可显示

检测浏览器/设备是不是支持双击事件

检测 Iframe 内容何时加载(跨浏览器)