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


当前回答

在此我将针对Android用户添加一条建议。您可以这样做,从而避免获得任何外部库。此外,上面一些答案中建议的所有搜索/替换字符解决方案都是危险的,应该避免。

试一试:

String urlStr = "http://abc.dev.domain.com/0007AC/ads/800x480 15sec h.264.mp4";
URL url = new URL(urlStr);
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
url = uri.toURL();

您可以看到,在这个特定的URL中,我需要对这些空格进行编码,以便我可以将其用于请求。

这利用了Android类中提供给你的几个功能。首先,URL类可以将URL分解为适当的组件,因此不需要进行任何字符串搜索/替换工作。其次,当您通过组件而不是从单个字符串构造URI时,这种方法利用了正确转义组件的URI类特性。

这种方法的美妙之处在于,您可以使用任何有效的url字符串并让它工作,而不需要您自己对它有任何特殊的了解。

其他回答

我创建了一个新项目来帮助构建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

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

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;
    }

}

如果你用的是弹簧,你可以试试 org.springframework.web.util.UriUtils # encodePath

uri类可以提供帮助;你可以在URL的文档中找到

注意,URI类在某些情况下确实执行组件字段的转义。建议使用URI来管理url的编码和解码

使用一个具有多个参数的构造函数,例如:

URI uri = new URI(
    "http", 
    "search.barnesandnoble.com", 
    "/booksearch/first book.pdf",
    null);
URL url = uri.toURL();
//or String request = uri.toString();

(URI的单参数构造函数不转义非法字符)


上面的代码只转义了非法字符——它不会转义非ascii字符(参见fatih的评论)。 toASCIIString方法可用于获取仅包含US-ASCII字符的String:

URI uri = new URI(
    "http", 
    "search.barnesandnoble.com", 
    "/booksearch/é",
    null);
String request = uri.toASCIIString();

对于像http://www.google.com/ig/api?weather=São Paulo这样的查询URL,使用构造函数的5个参数版本:

URI uri = new URI(
        "http", 
        "www.google.com", 
        "/ig/api",
        "weather=São Paulo",
        null);
String request = uri.toASCIIString();

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");

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