Programmatically accessing an iframe that uses a d

2019-04-06 04:20发布

I'm creating an iframe programmatically using the "data" URI:

<iframe id="myFrame" src='data:text/html;charset=utf-8,<!DOCTYPE html><html><head></head><body><h1>Hello.</h1></body></html>'></iframe>​

This frame loads fine, but it seems that working with the iframe programmatically hits cross-domain security checks.

var iframeDoc = document.getElementById('myFrame').contentWindow.document;
$(iframeDoc.body).find('h1').text('Changed');

Throws an error in Chrome and Safari:

Unsafe JavaScript attempt to access frame with URL data:text/html;charset=utf-8,... from frame with URL http://... The frame requesting access has a protocol of 'http', the frame being accessed has a protocol of ''. Protocols must match.

Here's a fiddle showing the security error: http://jsfiddle.net/bhGcw/4/

Firefox and Opera do not throw this exception and allow the iframe contents to be changed. Seems like Webkit sees a blank protocol for data URIs, and sees this as a cross-domain violation.

Is there any way around this?

3条回答
▲ chillily
2楼-- · 2019-04-06 04:48

It appears that Webkit does a simple string comparison in their domain checking code:

String DOMWindow::crossDomainAccessErrorMessage(DOMWindow* activeWindow)
{
    ...

    SecurityOrigin* activeOrigin = activeWindow->document()->securityOrigin();
    SecurityOrigin* targetOrigin = document()->securityOrigin();
    if (targetOrigin->protocol() != activeOrigin->protocol())
        return message + " The frame requesting access has a protocol of '" + activeOrigin->protocol() + "', the frame being accessed has a protocol of '" + targetOrigin->protocol() + "'. Protocols must match.\n";

    ...
}

It looks like Chromium is being more strict than the HTML5 spec, at least according the following bug reports:

Chromium devs don't seem to be in favor of relaxing this rule. Bummer.

查看更多
Lonely孤独者°
3楼-- · 2019-04-06 04:49

It's a bit late, how about instead of using a data URL, you use the HTML5 attribute srcdoc.

<iframe id="iframe" srcdoc='<html><body><h1>Hello!</h1></body></html>'></iframe>
<script type="text/javascript">
    $(function(){
        $($("iframe")[0].contentWindow.document).find("h1").text("Modified from the parent window!");
    });
</script>

There's an example at http://jsfiddle.net/ff3bF/

查看更多
家丑人穷心不美
4楼-- · 2019-04-06 05:01

The answer put forward by @jamie works well for loading HTML into an iframe and allowing subsequent programatic interaction with the content document.

XHTML is not so easy.

The srcdoc attribute appears to be limited to HTML, not XHTML.

A work around is to use a Blob URL which allows the content-type to be specified.

var documentSource = '<?xml version="1.0" encoding="UTF-8"?>\n<html xmlns="http://www.w3.org/1999/xhtml">\n<head>...';
var blob = new Blob([documentSource], { type: "application/xhtml+xml" });
iframe.src = URL.createObjectURL(blob);

This technique works for at least Chrome, Firefox and Safari.

查看更多
登录 后发表回答