我的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表单编码的实用程序类”…还有别的办法吗?


当前回答

我用这个

org.apache.commons.text.StringEscapeUtils.escapeHtml4("my text % & < >");

添加这个依赖项

 <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>1.8</version>
    </dependency>

其他回答

我也有同样的问题。通过unsing解决了这个问题:

android.net.Uri.encode(urlString, ":/");

它对字符串进行编码,但跳过“:”和“/”。

URL编码会对那个字符串进行编码这样它就能在URL中正确地传递到最终目的地。例如,您不能使用http://stackoverflow.com?url=http://yyy.com。UrlEncoding参数将修复该参数值。

所以我给你两个选择:

您是否有权访问与域分离的路径?如果是这样,您可以简单地对路径进行UrlEncode。然而,如果情况并非如此,那么选择2可能适合你。 commons - httpclient 3.1。它有一个类URIUtil: System.out.println(URIUtil.encodePath("http://example.com/x y", "ISO-8859-1"));

这将输出您正在寻找的内容,因为它只对URI的路径部分进行编码。

供您参考,这个方法需要common -codec和common -logging才能在运行时工作。

我把上面的内容做了一些改变。我首先喜欢正逻辑,并且我认为HashSet可能比其他选项(比如通过String进行搜索)提供更好的性能。虽然,我不确定自动装箱的代价是否值得,但如果编译器针对ASCII字符进行了优化,那么装箱的代价就会很低。

/***
 * Replaces any character not specifically unreserved to an equivalent 
 * percent sequence.
 * @param s
 * @return
 */
public static String encodeURIcomponent(String s)
{
    StringBuilder o = new StringBuilder();
    for (char ch : s.toCharArray()) {
        if (isSafe(ch)) {
            o.append(ch);
        }
        else {
            o.append('%');
            o.append(toHex(ch / 16));
            o.append(toHex(ch % 16));
        }
    }
    return o.toString();
}

private static char toHex(int ch)
{
    return (char)(ch < 10 ? '0' + ch : 'A' + ch - 10);
}

// https://tools.ietf.org/html/rfc3986#section-2.3
public static final HashSet<Character> UnreservedChars = new HashSet<Character>(Arrays.asList(
        'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
        'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
        '0','1','2','3','4','5','6','7','8','9',
        '-','_','.','~'));
public static boolean isSafe(char ch)
{
    return UnreservedChars.contains(ch);
}

也许可以试试org.springframework.web.util中的UriUtils

UriUtils.encodeUri(input, "UTF-8")

如果你的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