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


当前回答

我创建了一个新项目来帮助构建HTTP url。库将自动URL编码路径段和查询参数。

您可以在https://github.com/Widen/urlbuilder上查看源代码并下载二进制文件

这个问题中的URL示例:

new UrlBuilder("search.barnesandnoble.com", "booksearch/first book.pdf").toString()

生产

http://search.barnesandnoble.com/booksearch/first%20book.pdf

其他回答

请注意,上面的大部分答案都是不正确的。

URLEncoder类,不管它的名字,不是这里需要的。不幸的是,Sun给这个类命名得如此烦人。URLEncoder用于作为参数传递数据,而不是用于对URL本身进行编码。

换句话说,“http://search.barnesandnoble.com/booksearch/first book.pdf”是URL。参数可以是,例如,“http://search.barnesandnoble.com/booksearch/first book.pdf?parameter1=this&param2=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

我用这个

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

添加这个依赖项

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

我开发了一个比其他解决方案更稳定的解决方案:

public class URLParamEncoder {

    public static String encode(String input) {
        StringBuilder resultStr = new StringBuilder();
        for (char ch : input.toCharArray()) {
            if (isUnsafe(ch)) {
                resultStr.append('%');
                resultStr.append(toHex(ch / 16));
                resultStr.append(toHex(ch % 16));
            } else {
                resultStr.append(ch);
            }
        }
        return resultStr.toString();
    }

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

    private static boolean isUnsafe(char ch) {
        if (ch > 128 || ch < 0)
            return true;
        return " %$&+,/:;=?@<>#%".indexOf(ch) >= 0;
    }

}

如果你有一个URL,你可以将URL . tostring()传递给这个方法。首先解码,以避免双重编码(例如,编码空格会得到%20,编码百分号会得到%25,因此双重编码将把空格变成%2520)。然后,像上面解释的那样使用URI,添加URL的所有部分(这样就不会删除查询参数)。

public URL convertToURLEscapingIllegalCharacters(String string){
    try {
        String decodedURL = URLDecoder.decode(string, "UTF-8");
        URL url = new URL(decodedURL);
        URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); 
        return uri.toURL(); 
    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}

URLEncoding可以很好地编码HTTP url,正如您不幸发现的那样。您传入的字符串“http://search.barnesandnoble.com/booksearch/first book.pdf”被正确且完整地编码为url编码的表单。你可以把你得到的整个冗长的字符串作为URL的参数传递回去,它可以被解码成你传递进去的字符串。

听起来,您想要做一些与将整个URL作为参数传递不同的事情。据我所知,你试图创建一个看起来像“http://search.barnesandnoble.com/booksearch/whateverTheUserPassesIn”的搜索URL。你唯一需要编码的是“whateverTheUserPassesIn”位,所以也许你所需要做的就是这样:

String url = "http://search.barnesandnoble.com/booksearch/" + 
       URLEncoder.encode(userInput,"UTF-8");

这应该会产生一些对你更有效的东西。