转自:
http://www.cnblogs.com/_franky/archive/2012/09/28/2706512.html
IE10+, Safari5.17+, Firefox4.0+,Opera12+, Chrome7+ 已经按新标准实现. 所以就没有这个问题了.
参考标准 : http://www.w3.org/html/ig/zh/wiki/HTML5/tokenization 新标准明确提到,如果实体后面遇到的不是;且下一个是= 那么就不处理的.就是为了解决这个坑爹的问题的.
我们来看demo :
部分浏览器(对应上面已经按新标准实现的版本之下的,各个浏览器.)
点上面的链接, 会自动把 ® 转意成® (部分浏览器会自动对转意后的字符进行编码) .
这个bug.的本质,就是当HTML中出现相关HTML实体(HTML character entity)时.就自动转意处理了. 所以理论上, 用脚本,动态创建的资源则没有这个问题,比如 new Image().src = 'http://www.baidu.com?a=1®=2'; 甚至动态创建的iframe.亦如此.
IE9- 有两个问题比其他浏览器更严重:
1. 用脚本跳转当前页比如location.href = xxx,或 location.replace(xxx) .又或者是调用window.open(xxx);如果查询字符串中包含这些html实体, 仍然会触发这个问题...
2. ,参见标准, 你会知道实体+"其他字符" , "其他字符中",哪些与实体连接在一起,是没有这个问题的. 比如 ®a , ®1 其中a, 1 与 ® 连接就不会有这种问题,从标准角度,甚至是 ®_a 也不应有问题. 但是IE9-又一次打败了我们. 至于其他特殊字符如 # ~ 等.在各个浏览器中表现各异. 考虑我们在设计字段名时,不大可能出现那些字符.我们也不再纠结其他浏览器在此处实现的差异.
所以,理论上,这个问题应该是后端的同学,在输出html时.更加要注意的问题. 而前端同学,要注意的则是跳转或弹窗时的url中是否有相关的字段包含一个无分号即为html实体的情况.
至于IE为啥这么特殊...我也没想明白...
那么,无论后端同学也好,前端同学也罢,我们可能更改已经定好的字段成本比较高. 所以其实最妥善的办法,应该是这样子: (感谢 @辰光未然 的提醒.)
var
fixURL =
function
(url) {
return
url.replace(/&/g,
'&'
);
};
//使用fixURL 去替换url中的&.然后再输出给html, 或者跳转链接,又或者弹窗... 当然,前端的同学在js代码中之所以要这样做.主要是受IE的拖累...
|
那么大概,很多HTML 实体都会出问题:
http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html#named-character-references
这个表里, 没有分号结尾的,都是隐患... 也就是下面这106个: (感谢 @kenny 提供的最新的list 地址. 我花了点时间写了个脚本.把需要处理的,都抓了出来.)
我们可以用下面这个脚本来帮忙做检测 :
var
checkURL =
function
() {
var
list = [
//106
'Á'
,
'á'
,
'Â'
,
'â'
,
'´'
,
'Æ'
,
'æ'
,
'À'
,
'à'
,
'&'
,
'&'
,
'Å'
,
'å'
,
'Ã'
,
'ã'
,
'Ä'
,
'ä'
,
'¦'
,
'Ç'
,
'ç'
,
'¸'
,
'¢'
,
'©'
,
'©'
,
'¤'
,
'°'
,
'÷'
,
'É'
,
'é'
,
'Ê'
,
'ê'
,
'È'
,
'è'
,
'Ð'
,
'ð'
,
'Ë'
,
'ë'
,
'½'
,
'¼'
,
'¾'
,
'>'
,
'>'
,
'Í'
,
'í'
,
'Î'
,
'î'
,
'¡'
,
'Ì'
,
'ì'
,
'¿'
,
'Ï'
,
'ï'
,
'«'
,
'<'
,
'<'
,
'¯'
,
'µ'
,
'·'
,
' '
,
'¬'
,
'Ñ'
,
'ñ'
,
'Ó'
,
'ó'
,
'Ô'
,
'ô'
,
'Ò'
,
'ò'
,
'ª'
,
'º'
,
'Ø'
,
'ø'
,
'Õ'
,
'õ'
,
'Ö'
,
'ö'
,
'¶'
,
'±'
,
'£'
,
'"'
,
'"'
,
'»'
,
'®'
,
'®'
,
'§'
,
'­'
,
'¹'
,
'²'
,
'³'
,
'ß'
,
'Þ'
,
'þ'
,
'×'
,
'Ú'
,
'ú'
,
'Û'
,
'û'
,
'Ù'
,
'ù'
,
'¨'
,
'Ü'
,
'ü'
,
'Ý'
,
'ý'
,
'¥'
,
'ÿ'
];
return
function
(url) {
var
l = list;
var
i = l.length;
var
matchIndex;
var
current;
var
nextchar;
var
errors = [];
for
(; i--;){
matchIndex = url.indexOf(l[i]);
current = l[i];
if
(matchIndex > -1){
if
((current ===
'&'
|| current ===
'&'
) && url.charAt(matchIndex + 4) ===
';'
){
//如果是 & 或 & 我们就认为是故意要输出 & ,比如是一个调用fixURL方法修正过的URL.里面的& 会被我们替换为 amp;
//所以,我们要跳过它,去检查后面.
continue
;
}
nextchar = url.charAt(matchIndex + current.length);
if
(!/[a-zA-Z0-9]/.test(nextchar)){
//此处我们只要发现任意一个 ,如 ®后面紧随字符不在 a-z,A-Z,0-9范围内.就算有问题.
//这样处理实际和标准的细节以及浏览器实现有细微差异. 但是本着任何浏览器来跑case,
//都能发现潜在威胁的原则.和实现复杂度的考虑.
// 我们姑且粗暴的这样处理了. 似乎还不错.
errors.push(current + nextchar);
}
}
}
if
(errors.length){
throw
Error(
'contains : \n'
+ errors.join(
'\n'
));
}
};
}();
|
test case 1:
var
url =
'//www.baidu.com?a=1&=2<=3®=4'
;
document.onclick =
function
() {
//IE9-好了.证明我们的修正是ok的了.
window.open(fixURL(url))
};
|
test case 2:
var
url =
'//www.baidu.com?a=1&=2<=3®=4'
;
try
{
checkURL(url);
}
catch
(e){
alert(e.message)
}
|