题 如何编码URL以避免Java中的特殊字符? [重复]


这个问题在这里已有答案:

我需要java代码来编码URL,以避免使用空格和%和&...等特殊字符


31
2017-12-31 17:12


起源


这种问题正是某些网站永远不会在其网址中使用需要转义/编码的字符的原因。 堆栈溢出 似乎是这样一个网站(只看一下干净的URL)。我认为人们链接到URL中的文件,例如,在名称中间隔字符(以及在文件中使用间距字符的人)应该被拍摄。那些与这个事实争论的人更是如此;) - SyntaxT3rr0r
(@fmucar在下面的答案中建议重复)。 - halfer


答案:


URL构造很棘手,因为URL的不同部分对允许的字符具有不同的规则:例如,加号在URL的查询组件中保留,因为它表示空格,但在URL的路径组件中,加号没有特殊含义,空格编码为“%20”。

RFC 2396 解释(在2.4.2节中)完整的URL始终采用其编码形式:您获取各个组件的字符串(方案,权限,路径等),根据自己的规则对每个组件进行编码,然后将它们组合在一起进入完整的URL字符串。尝试构建一个完整的未编码的URL字符串,然后单独编码会导致细微的错误,例如路径中的空格被错误地更改为加号(符合RFC的服务器将解释为真实加号,而不是编码空格)。

在Java中,构建URL的正确方法是使用 URI 类。使用其中一个多参数构造函数将URL组件作为单独的字符串,它将根据该组件的规则正确地转义每个组件。该 toASCIIString() method为您提供了可以发送到服务器的正确转义和编码的字符串。至 解码 一个URL,构造一个 URI 对象使用单字符串构造函数然后使用访问器方法(例如 getPath())检索解码的组件。

不要使用 URLEncoder 类!尽管名称,该类实际上做HTML表单编码,而不是URL编码。它的  正确连接未编码的字符串以生成“未编码”的URL,然后将其传递给 URLEncoder。这样做会导致问题(特别是前面提到的关于空间和路径中的加号的问题)。


64
2017-12-31 17:50



我想把它写成mysekf ....它是否正确? public static String encode(String str){StringBuilder sb = new StringBuilder(); for(int i = 0; i <str.length(); i ++){switch(str.charAt(i)){case'':sb.append(“%20”); break; case'!':sb.append(“%21”); break; case'“':sb.append(”%22“); break;默认值:sb.append(str.charAt(i));}}返回sb.toString();} - Adham
@adham,不,正确的URL编码不仅仅是转义这三个字符。该代码可能会产生正确的结果 一些 URL,但有许多它无法正确处理。只需使用 URI 类。 - Wyzard
是的,我知道还有很多其他角色......但是你可以为URI类提供一个简单的例子 - Adham
从测试开始,您似乎仍然需要使用“+”符号手动替换查询中的空格。我在某处犯了错误吗? - Edward Falk
@EdwardFalk,你是对的, URI 似乎没有在查询字符串中将空格转换为'+'。我可以发誓这样做,因为我在解决我自己的代码中的空间/加问题时学习了URI类,但那是几年前我不记得细节了。由于加号实际上是其中的一部分 application/x-www-form-urlencoded MIME类型而不是URI语法本身,我想通过a运行(仅)查询字符串是有意义的 URLEncoder 把它放入之前 URI。不过,我需要重新考虑并重写我的答案。 - Wyzard


这是以下问题的副本。您可以在以下问题中找到有关此问题的更多详细信息和讨论

Java中的HTTP URL地址编码

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

}

10
2018-01-05 15:31





如果您不想手动使用Apache Commons - Codec库。你正在看的课程是: org.apache.commons.codec.net.URLCodec

String final url = "http://www.google.com?...."
String final urlSafe = org.apache.commons.codec.net.URLCodec.encode(url);

5
2017-12-31 17:17



为什么这个答案得到了落实? - Christian Vielma
只是一个说明。 URLCodec意味着替代URLEncoder / URLDecoder。编码整个网址并不重要,这就是示例所示。意思是甚至http://变成http%3A%2F%2F。除非那是你想要做的。 - Nicholi
两者都给我相同的“错误”结果URLCodec urlCodec = new URLCodec(); System.out.println(urlCodec.encode(“FOO BAR”)); // FOO + BAR System.out.println(URLEncoder.encode(“FOO BAR”,“UTF-8”)); FOO + BAR - Topera


我会回应什么 威兹德写道 但补充一点:

  • 对于查询参数,HTML编码通常正是服务器所期望的;在这些之外,这是正确的 URLEncoder 不应该使用
  • 最新的URI规范是 RFC 3986,所以你应该把它作为主要来源

我不久前写了一篇关于这个主题的博客文章: Java:安全的字符处理和URL构建


1
2017-12-31 20:09





我也花了很长时间来解决这个问题,所以这是我的解决方案:

String urlString2Decode = "http://www.test.com/äüö/path with blanks/";
String decodedURL = URLDecoder.decode(urlString2Decode, "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());
String decodedURLAsString = uri.toASCIIString();

1
2018-01-17 23:08





这是我的解决方案,非常简单:

而不是编码网址本身我编码我传递的参数,因为参数是用户输入,用户可以输入任何意外的特殊字符串,所以这对我很好:)

String review="User input"; /*USER INPUT AS STRING THAT WILL BE PASSED AS PARAMTER TO URL*/
try {
    review = URLEncoder.encode(review,"utf-8");
    review = review.replace(" " , "+");
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}
String URL = "www.test.com/test.php"+"?user_review="+review;

-1
2017-09-19 07:33



对不起,我意外地做了,但这个解决方案有效。 - Shahid Sarwar