问题
在对URL进行encode编码的时候,URL中的空格有时候被编码成%20
,有时候被编码成加号+
。大多数情况下,这两种编码都可以工作,但个别情况下,编码为+
的URL存在问题,并不能正常访问。
原因
一个URL的基本组成部分包括协议(scheme),域名,端口号,路径和查询字符串(路径参数和锚点标记就暂不考虑了)。路径和查询字符串之间用问号?分离。
例如http://www.example.com/index?param=1
,路径为index
,查询字符串(Query String)为param=1
。
以上例子中URL中关于空格的编码正是与空格所在位置相关:空格被编码成加号+的情况只会在查询字符串部分出现,而被编码成%20则可以出现在路径和查询字符串中。
造成这种混乱局面的原因在于:W3C标准规定,当Content-Type
为application/x-www-form-urlencoded
时,URL中查询参数名和参数值中空格要用加号+替代,所以几乎所有使用该规范的浏览器在表单提交后,URL查询参数中空格都会被编成加号+
。
而在另一份规范(RFC 2396,定义URI)里, URI里的保留字符都需转义成%HH
格式(Section 3.4 Query Component),因此空格会被编码成%20
,加号+
本身也作为保留字而被编成%2B
,对于某些遵循RFC 2396
标准的应用来说,它可能不接受查询字符串中出现加号+
,认为它是非法字符。所以一个安全的举措是URL中统一使用%20
来编码空格字符。
解决方法(java)
Java中的URLEncoder本意是用来把字符串编码成application/x-www-form-urlencoded MIME
格式字符串,也就是说仅仅适用于URL中的查询字符串部分,但是URLEncoder
经常被用来对URL的其他部分编码,它的encode
方法会把空格编成加号+
,与之对应的是,URLDecoder
的decode
方法会把加号+
和%20
都解码为空格,这种做法造成了URL编码问题的混乱。
比较可靠的做法是,在调用URLEncoder.encode
对URL进行编码后(所有加号+
已被编码成%2B
),再调用replaceAll(“\\+”, “%20″)
,将所有加号+
替换为%20
。例子如下:
public static String urlEncodeURL(String url) {
try {
String result = URLEncoder.encode(url, "UTF-8");
result = result.replaceAll("%3A", ":").replaceAll("%2F", "/").replaceAll("\\+", "%20");//+实际上是 空格 url encode而来
return result;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}