在调查一个错误的时候,偶然发现HTML页面中的部分Link含有+,将tag反编译了一下,发现是因为调用了java.net.URLEncoder的方法
public static String encode(String s, String enc)
从代码中可以很清晰的看到还特别照顾的将' '转成了'+'。由于印象中的URL编码规则应该是将空格转为%20,就google了一把,结果发现很多人都遇到了这个问题,但基本都是语焉不详。
花了1个多小时仔细搜索了一遍,线索如下:
1、在sun的bug库中找到有人认为该方法不符合RFC2396标准
http://bugs.sun.com/view_bug.do?bug_id=4616184
sun的回答说不是bug,符合HTML4.01标准
2、在W3C找到HTML标准的说明
http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4
在这里清楚的看到编码方式是根据ContextType的不同而区别对待的,在form的ContextType是[x-www-form-urlencoded]的时候会对form中的键/值对进行编码,空格被转义成+,其他字符按照[RFC1738]标准处理成%HH的形式。
3、回头再看URLEncoder
发现该类的注释中很明确的写明了:
converting a String to the application/x-www-form-urlencoded MIME format
从以上的结果看来%20似乎只是在使用上的一个误解,因为%20可以被解析成空格,所以就理所当然的认为空格应该被转义为%20。
再进一步,对Java/.Net/JavaScript的相关函数进行下测试,结果发现Java(1.5)与.Net(2.0)的情况一致,但JavaScript的函数还是将空格转换成了%20。看来这个问题的误解完全来自于js的错误……
try ...{
System.out.println(URLEncoder.encode("Hello World","UTF-8"));
System.out.println(URLDecoder.decode("Hello+World","UTF-8"));
System.out.println(URLDecoder.decode("Hello%20World","UTF-8"));
} catch (UnsupportedEncodingException e) ...{
e.printStackTrace();
}
}
... {
Console.WriteLine(HttpUtility.UrlEncode("Hello World"));
Console.WriteLine(HttpUtility.UrlDecode("Hello World"));
Console.WriteLine(HttpUtility.UrlDecode("Hello%20World"));
}
document.write(escape( ' Hello World ' ) + ' <BR> ' );
document.write(unescape( ' Hello+World ' ) + ' <BR> ' );
document.write(unescape( ' Hello%20World ' ));
</ script >
<script type=text/javascript>AddFeedbackCountStack("2300225")</script>