首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么使用HTMLObjectElement动态生成SVG会导致跨域错误?

为什么使用HTMLObjectElement动态生成SVG会导致跨域错误?
EN

Stack Overflow用户
提问于 2017-10-25 18:15:42
回答 2查看 859关注 0票数 19

请考虑以下JavaScript代码片段:

代码语言:javascript
复制
const app = document.getElementById('root');
const svg = `<svg version="1.1" id="Layer_1"...`;
const obj = document.createElement('object');

obj.setAttribute('type', 'image/svg+xml');
obj.setAttribute('data', `data:image/svg+xml; base64,${btoa(svg)}`);

app.appendChild(obj);

setTimeout(() => {
  console.log(obj.contentDocument.querySelector('svg'));
}, 1500);

(有关完整示例,请参阅 )

运行此命令时,控制台(Google Chrome)中会显示以下错误:

HTMLObjectElement未捕获DOMException:未能从“”HTMLObjectElement“”中读取“”contentDocument“”属性:阻止具有源“"https://fiddle.jshell.net”“的帧访问跨域帧。”“在setTimeout (https://fiddle.jshell.net/_display:77:19)

考虑到这一点;

  1. 当尝试访问完全动态创建的、没有外部资源的对象的contentDocument时,这为什么被认为是跨域请求?
  2. 有没有办法以这种方式动态生成SVG,而不会触犯浏览器的跨域策略?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-10-27 22:34:47

这里的问题是,data: URLs are treated as having a unique origin与创建嵌入式data:上下文的上下文的来源不同:

注意:现代浏览器将数据URL视为唯一的不透明来源,而不是继承负责导航的设置对象的来源。

WHATWG规范描述了how content documents are accessed,它包括交叉来源检查。WHATWG same-origin comparison永远不会将传统方案-主机-端口“元组”来源等同于“不透明”的data:来源。

取而代之的是,使用带有URL.createObjectURLBlob来生成一个同源的临时URL,其内容将由外部环境读取:

代码语言:javascript
复制
var svgUrl = URL.createObjectURL(new Blob([svg], {'type':'image/svg+xml'}));
obj.setAttribute('data', svgUrl);

我不知道这种方法被允许而原始data: URL不被允许的安全原因,但它似乎确实有效。(我猜是因为生成的URL只能由生成它的源读取,而data: URL不知道如何只由其原始上下文的原始上下文读取。)

另请注意,某些版本的Internet Explorer支持createObjectURL,但错误地将生成的URL视为具有空源,这将导致此方法失败。

其他选项包括:

SVG不要使用SVG,而是从创建

const obj = document.createElement('div');obj.innerHTML = svg;app.appendChild(obj);setTimeout(() => { console.log(obj.querySelector('svg'));},1500);

大多数浏览器都支持内联<svg>元素(特别是IE 9.0+;其他浏览器要早得多)。这意味着你可以根据你想要对SVG做什么来做

var oParser =新的DOMParser();var svgDOM = oParser.parseFromString(svg,“文本/xml”);var

但是DOM模型将与在<object>中呈现的SVG分开。要更改<object>,您需要序列化已解析的DOM结构,并将其重新推送到data属性:

var oSerializer =新数据();var sXML = oSerializer.serializeToString(svgDOM);obj.setAttribute('data',data:image/svg+xml; base64,${btoa(sXML)});

这看起来性能不是很好,因为它需要浏览器重新解析一个全新的SVG文档,但它将绕过安全限制。

可以将<object>看作一个单向黑洞,它可以接收要呈现的SVG信息,但不会公开任何返回的信息。不过,这不是一个信息学问题,因为您拥有刚刚输入到<object>中的信息:contentDocument可以告诉您的信息都是您已经知道的。

但是,如果您想通过将侦听器附加到在主页上执行代码的SVG结构中的组件来使SVG中的组件具有交互性,我认为这种方法是行不通的。与<iframe>.一样,<object>与其周围页面之间的分隔具有相同的嵌入关系

票数 14
EN

Stack Overflow用户

发布于 2017-10-27 22:19:21

因为object标记在HTML文档中定义了一个嵌入的对象,所以它不是文档本身的一部分,因此必须像框架一样尊重CORS

Same-origin policy

here清楚地指出,object标记的内容被视为外部资源

元素表示外部资源,可以将其视为图像、嵌套的浏览上下文或要由插件处理的资源。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46929730

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档