Ie9的奇葩bug iframe的load事件监听
微软为了向标准靠拢,同时为了向后兼容,在IE9中,如果监听元素的事件的话,两种方法addEventListener
和attachEvent
都是可以用的;理论上来说应该是没有什么区别的,但是在最近项目上的一个小功能上需要用到iframe个form表单配合上传文件,这时候就遇到了奇葩的IE9产生的一个bug:
IE9中iframe的load事件不会被触发,虽然从请求上来看,已经成功,也有响应
下面详细说下这个奇幻漂流之旅。
对比
由于这个功能需要android和ios客户端上建立简易server,而bug是在android手机上测试发现的,在ios上并没有这个bug,所以就是对比,查看请求响应有什么不同。
结果发现:
-
在ios上响应头
Connection
是close
,而在android上没有。 -
在ios上响应头
Content-Type
是text/plain; charset=utf-8
,而在android上响应的类型Content-Type
是text/json; charset=utf-8
。
对于第1点,只是对于此次连接是否断开(close)或者保持(keepalive),没有啥问题。详见HTTP协议头部与Keep-Alive模式详解博文。
所以就猜测是响应类型导致的问题。但是这个text/json是什么东东?
response的content-type的值,一般是如下几种情况:
-
服务端需要返回一段普通文本给客户端
-
务端需要返回一段HTML代码给客户端
-
服务端需要返回一段XML代码给客户端
-
服务端需要返回一段javascript代码给客户端
-
服务端需要返回一段json串给客户端
对于前3中对于的content-type分别为text/plain
、text/html
、和text/xml
;而对于一段javascript代码来说,按照最新标准写法是大家都知道的application/javascript
,而常用的text/javascript
已经被废弃了(rfc4329);对于响应是json的,常见写法有text/json
、text/javascript
,但是最新的标准是application/json
(rfc4627),这个text/json
本应不存在的,百度谷歌了一阵,没什么有用的价值,大致意思就是
text/json在android手机应用客户端和服务器端传送数据时用到
或者
某些情况下,每次请求都要指定Content-Type:text/json。否则服务器会收不到请求参数或出错。
所以解决方案就是请android组同事帮忙改下响应头。到这里就结束了吗?android组同事在解决是需要时间的;我总觉得还是差点什么,为什么响应头影响到了iframe的load事件的触发??
尝试addEventListener
和attachEvent
大胆猜测下,这两张监听事件的方法有什么不同吗?或者说在某些场景下会有什么不同吗?
iframe监听大尝试
这次只是针对于iframe的load事件的监听,首先直接使用iframe.onload = function() {}
,实验发现能正常的触发load事件;接着使用iframe.attachEvent('onload', function() {})
,发现也是可以触发的,这下就奇怪了,难道就addEventListener
不可以,所以最后实验iframe.addEventListener('load', function() {})
,果不其然,load事件不会被触发。
这真是惊天真相,这还会有区别?那对于其他元素会有bug吗?
button监听大尝试
这次创建button
元素,然后监听click
事件,事实证明三种方式都是可以的,没有问题。那如果是关于load
事件的呢?
img监听大尝试
创建img
元素,监听load
事件。也都无问题。
目前来看只有iframe有这个不可思议的问题。
结局
结局很简单,那就是android组同事把响应头content-type
改为text/plain
了,而js部分没有变,问题得到解决了。
虽然说是一个本不应存在的content-type:text/json
引起的,但是对于IE9,这种不会触发load
事件bug实在是万万不能想到的。
最后,仍然把js代码判断应该用addEventListener
或者attachEvent
的部分稍稍修改了下,由
function addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
}
变为了
function addEvent(element, type, handler) {
if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else {
element["on" + type] = handler;
}
}
好,到这里奇幻漂流之旅结束了,但是也有感慨:。。。省略。。。
参考: