为什么这个document.write iframe广告代码会完全破坏Internet Explorer?

13

我正在尝试找到为什么出现这个问题的答案;虽然我已经解决了这个问题,但我想知道它发生的原因。

简述

通过使用非document.write方法注入相同的 iframe 可以解决突然导致所有版本的 Internet Explorer 停止执行页面的 Google 提供的转化跟踪代码,该代码使用 document.write 注入了一个 iframe。

故事背景:

Doubleclick 是一个广告网络,提供 JavaScript 代码来跟踪广告的转化情况。

他们提供的代码如下:

<SCRIPT language="JavaScript">
var axel = Math.random()+"";
var a = axel * 10000000000000;
document.write('<IFRAME SRC="https://fls.doubleclick.net/activityi;src=143;type=donat01;cat=indir4;ord=1;num='+ a + '?" WIDTH=10 HEIGHT=10 FRAMEBORDER=0></IFRAME>');
</SCRIPT>
<NOSCRIPT>
<IFRAME SRC="https://fls.doubleclick.net/activityi;src=143;type=donat01;cat=indir4;ord=1;num=1?"
WIDTH=1 HEIGHT=1 FRAMEBORDER=0></IFRAME>
</NOSCRIPT>

我知道由于各种原因,document.write存在风险并应该避免使用。但是,谷歌给了我这段代码,所以我认为我可以相信它。

它突然开始破坏我们所有在Internet Explorer中使用的页面。也就是说,一旦它碰到document.write,页面将完全停止呈现。这太疯狂了:互联网上最大的第三方广告商给了我JavaScript,导致我的25%流量的购买页面被“真正”破坏!

为了快速处理,我迅速尝试使用在Google Analytics中发现的注入技术替换了相同的代码:

var iframe = document.createElement('iframe');
iframe.src = //the URL;
iframe.width = 0;
iframe.height = 0;
iframe.frameborder = 0;
var ref = document.getElementsByTagName('script')[0];
ref.parentNode.insertBefore(iframe, ref);

这样解决了问题,但并没有解释原因:

为什么使用document.write注入一个几乎为空的iframe会破坏Internet Explorer,但是上面的方法不会?


11
可能是因为你不应该使用document.writeiframe或者Internet Explorer :) - jtbandes
完全同意您的三点观点 :) 不幸的是,我的听众中有25%使用IE,并且这个document.write iframe代码在互联网上被广泛使用,但据我所知,这个问题似乎没有被记录。 - Yahel
3
哦,请。Internet Explorer 完全崩溃了自己。 - Lightness Races in Orbit
1
@TomalakGeret'kal 这是 Doubleclick floodlight 标签的跟踪代码。这个标签的某种变体出现在前 10,000 个网站中的 14.5% 上。http://trends.builtwith.com/ads/DoubleClick.Net 虽然有几种变体,但这是最广泛使用的一种。 - Yahel
2
@TomalakGeret'kal 嗯,我完全同意。 - Yahel
显示剩余2条评论
6个回答

8
我已解决问题;原来这与<iframe>的内容无关。
实际上,页面由一个框架提供服务,该框架开始使用后端DOM解析器,由于<script>标签中存在</,它完全从生成的页面中删除了</iframe>闭合标记,尽管它在后端保留它。(它可能试图强制执行 ETAGO 规则)
之所以能够重现它是因为我复制的是生成的document.write代码,而不是原始代码,从未注意到缺少的</iframe>。(我的“运作正常”的document.write代码没有被剥离</iframe>标记,导致我认为问题出在iframe的内容。)
因此,浏览器在页面上解析了一个未关闭的<iframe>标签,而Internet Explorer不知道如何处理它,在解析iframe的过程中死机了(我仍然不完全确定为什么)。

1
你尝试过将匹配的 document.write("</iframe>") 放置在页面后面的位置,看看会发生什么吗? - hugomg
错误消失了。所以,肯定是缺少的结束标签是罪魁祸首;此时,我只是好奇为什么IE会崩溃,而其他浏览器却能应对。 - Yahel
有趣!这个框架是公开可用的吗?肯定会导致许多浏览器出现问题,如果留下一个<iframe>(与留下<script>的常见错误相同),在JS字符串文字中通常应该使用'<\/'来避免它(或者如果您想在没有CDATA部分的XHTML中工作,则可以使用'\x3C/')。 - bobince
@bobince 不是的,但它使用PHP的DOMDocument来解析DOM,这就是行为引入的地方。我会尝试看看\x3C/是否可以防止解析器出现问题。 - Yahel
1
确认 DOMDocument::loadHTML 存在这种行为。它似乎试图使用 CDATA 部分修复包含 </ 的无效脚本块,但在这样做时会丢失一些内容,可能是意外的。是的,如果您将一些 HTML 提供给 DOMDocument,您必须确保传入的 HTML 实际上是有效的;任何避免编写直接 ETAGO 的方法都可以。 - bobince

0

document.write()会阻止页面的进一步渲染,直到它完成。我猜测远程脚本加载需要一些时间,因此阻止了页面的其余部分加载。

我还假设Math.Random()函数对此没有帮助。

另外...谷歌的跟踪代码让我感到害怕...它们往往是JavaScript的丑陋黑客。


1
Math.Random() 只是用于在 URL 上生成缓存破坏属性。速度似乎不是这里的问题;无论在哪种条件下,iframe URL 在所有其他浏览器中都以完全正常的速度响应。 - Yahel
@yahelc,页面上还有哪些其他 JavaScript 代码?在 IE 中,可能存在一个错误导致解析 JavaScript 失败,这会在 iframe 代码之前发生。 - timw4mail
页面没有错误,并使用IE Dev工具和Firebug Lite确认DOM解析在“document.write”处停止。我稍后会制作一个简单的演示。 - Yahel

0

第一种方法变慢的原因有两个。

  • document.write()会阻塞,直到它实际执行完毕
  • window.onload事件只有在所有iframe及其内部资源全部加载完成后才会触发

您的解决方案之所以有效,是因为它创建的iframe直到onload事件之后才请求远程url。如果在第一段代码中设置了超时,您也可以先加载页面,然后再请求远程url。

至于为什么更改代码会破坏网站,我似乎找不到在两者之间传输速度差异的任何证据。也许它看起来更快是因为它被缓存了。


它并没有“看起来更快”。在IE中,页面在document.write处停止加载。您是否有关于外部iframe内容延迟onload事件的文档? - Yahel
我尝试在本地创建所有文件,并没有遇到页面无法加载的问题。至于外部iframe,您可以在Google上找到很多相关信息 - http://stevesouders.com/efws/iframe-onload-blocking.php?type=img&t=1310045005 这里已经设置好了。 - Revolution42

0

我不清楚你网站的结构,但通常第一个脚本标签在 <head> 中。 <head> 中的 iframe 不会被渲染。 我敢打赌,如果你执行 document.body.getElementsByTagName('script')[0],你可能会遇到和上述描述类似的问题。


这不正确。你所说的版本在IE上没有问题;只有document.write版本在IE中才无法工作,并且仅在列出的情况下。我之前没有说明,但是document.write<body>标签中,而不是<head>标签中。<head>通常不显示的唯一原因是浏览器样式表将其设置为display:none;。浏览器仍然可以正常加载<head>中的资源;它只是不会物理显示它们。 - Yahel
那就是我的观点。我认为问题在于渲染,而不是加载。我怀疑添加 iframe 在这种情况下能够正常工作,因为它并没有被显示出来。我在想,如果你把这个 iframe 添加到一个会显示的地方会发生什么。 - cwallenpoole
有趣。我误解了。我会使用 document.body 作为注入点来编写一个测试用例,看看会发生什么。 - Yahel

0

看起来你遇到了我几个月前遇到的类似问题(链接)document.write 触发并覆盖页面。 直接使用 iframe,一切都应该没问题。


1
抱歉,这不正确。我并不是在尝试修复它 - 我通过使用异步注入来解决了问题。我正在努力弄清楚为什么这个特定的情况会出错。此外,这不是在 window.onload 后使用 document.write 的情况;那会导致页面变白。这只是停止了执行。 - Yahel

0

我尝试再IE9上复制你的问题,但未能成功。

要么是因为我没有正确的测试设置,要么就是IE 9之前的IE存在一些错误。Firefox也有一个类似的错误:https://bugzilla.mozilla.org/show_bug.cgi?id=293633

可能是由于未关闭的iframe和页面内的某些内容组合在一起导致的问题。


1
我没有访问IE9的权限,但是这个测试用例显示在IE6、IE7和IE8中存在这种行为。http://sharedcount.com/test/ie-dw-if/old.html 它是否显示一个写着"Text after iframe"的<h2>标签?如果是这样的话,那么IE9不应该表现出相同的行为。 - Yahel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接