我的Java独立应用程序从用户那里获得一个URL(指向一个文件),我需要点击它并下载它。我面临的问题是,我不能正确编码HTTP URL地址…
例子:
URL: http://search.barnesandnoble.com/booksearch/first book.pdf
java.net.URLEncoder.encode(url.toString(), "ISO-8859-1");
回报我。
http%3A%2F%2Fsearch.barnesandnoble.com%2Fbooksearch%2Ffirst+book.pdf
但是,我想要的是
http://search.barnesandnoble.com/booksearch/first%20book.pdf
(空格替换为%20)
我猜URLEncoder不是为编码HTTP url设计的…JavaDoc说“HTML表单编码的实用程序类”…还有别的办法吗?
请注意,上面的大部分答案都是不正确的。
URLEncoder类,不管它的名字,不是这里需要的。不幸的是,Sun给这个类命名得如此烦人。URLEncoder用于作为参数传递数据,而不是用于对URL本身进行编码。
换句话说,“http://search.barnesandnoble.com/booksearch/first book.pdf”是URL。参数可以是,例如,“http://search.barnesandnoble.com/booksearch/first book.pdf?parameter1=this¶m2=that”。参数是你使用URLEncoder的目的。
下面两个例子强调了两者之间的区别。
根据HTTP标准,下面会产生错误的参数。注意&号(&)和加号(+)编码错误。
uri = new URI("http", null, "www.google.com", 80,
"/help/me/book name+me/", "MY CRZY QUERY! +&+ :)", null);
// URI: http://www.google.com:80/help/me/book%20name+me/?MY%20CRZY%20QUERY!%20+&+%20:)
下面的代码将生成正确的参数,并对查询进行正确编码。注意空格、&号和加号。
uri = new URI("http", null, "www.google.com", 80, "/help/me/book name+me/", URLEncoder.encode("MY CRZY QUERY! +&+ :)", "UTF-8"), null);
// URI: http://www.google.com:80/help/me/book%20name+me/?MY+CRZY+QUERY%2521+%252B%2526%252B+%253A%2529
如果你的URL中有一个编码的“/”(%2F),这仍然是一个问题。
RFC 3986 -章节2.2说:“如果URI组件的数据与保留字符作为分隔符的目的相冲突,那么冲突的数据必须在URI形成之前进行百分比编码。”(rfc3986 -第2.2节)
但是Tomcat有一个问题:
http://tomcat.apache.org/security-6.html - Fixed in Apache Tomcat 6.0.10
important: Directory traversal CVE-2007-0450
Tomcat permits '\', '%2F' and '%5C'
[...] .
The following Java system properties
have been added to Tomcat to provide
additional control of the handling of
path delimiters in URLs (both options
default to false):
org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH:
true|false
org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH:
true|false
Due to the impossibility to guarantee
that all URLs are handled by Tomcat as
they are in proxy servers, Tomcat
should always be secured as if no
proxy restricting context access was
used.
Affects: 6.0.0-6.0.9
因此,如果您有一个含有%2F字符的URL, Tomcat将返回:"400 Invalid URI: noSlash"
你可以在Tomcat启动脚本中切换bug修复:
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG% -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
我阅读了以前的答案,写我自己的方法,因为我不能有一些正确的工作使用以前的答案的解决方案,它看起来对我很好,但如果你能找到不与此工作的URL,请让我知道。
public static URL convertToURLEscapingIllegalCharacters(String toEscape) throws MalformedURLException, URISyntaxException {
URL url = new URL(toEscape);
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
//if a % is included in the toEscape string, it will be re-encoded to %25 and we don't want re-encoding, just encoding
return new URL(uri.toString().replace("%25", "%"));
}
我开发了一个用于此目的的库:galimatias。它解析URL的方式与web浏览器相同。也就是说,如果一个URL在浏览器中工作,它将被galimatias正确解析。
在这种情况下:
// Parse
io.mola.galimatias.URL.parse(
"http://search.barnesandnoble.com/booksearch/first book.pdf"
).toString()
会给你:http://search.barnesandnoble.com/booksearch/first%20book.pdf。当然,这是最简单的情况,但它可以用于任何东西,远远超出java.net.URI。
你可以在https://github.com/smola/galimatias上查看