Java URL编码:URLEncoder vs. URI

23

查看 W3 Schools URL编码网页,它说@应该被编码为%40,而space应该被编码为%20

我尝试过URLEncoderURI,但是都不能正确地执行上述操作:

import java.net.URI;
import java.net.URLEncoder;

public class Test {
    public static void main(String[] args) throws Exception {

        // Prints me%40home.com (CORRECT)
        System.out.println(URLEncoder.encode("me@home.com", "UTF-8"));

        // Prints Email+Address (WRONG: Should be Email%20Address)
        System.out.println(URLEncoder.encode("Email Address", "UTF-8"));

        // http://www.home.com/test?Email%20Address=me@home.com
        // (WRONG: it has not encoded the @ in the email address)
        URI uri = new URI("http", "www.home.com", "/test", "Email Address=me@home.com", null);
        System.out.println(uri.toString());
    }
}

由于某些原因,URLEncoder 可以正确处理电子邮件地址但无法处理空格,而 URI 可以处理空格但无法处理电子邮件地址。

我应该如何对这两个参数进行编码,以与 W3Schools 给出的正确编码一致(或者是 W3Schools 错了?)


5
如果你在查看w3schools.com,那么你是在做错事。请参考此链接:http://w3fools.com/ - Srinivas
@Srinivas,我正在使用的 Web 服务明确忽略请求,除非参数按照 w3schools 网页上的说明进行编码 :( - John Farrelly
1
URLEncoder 不按照 URL 规范进行编码,而是按照 application/x-www-form-urlencoded MIME 格式进行编码(这是大多数应用服务器期望的参数键/值格式)。URI 类型根据其文档进行编码 - 也就是说,它不是一个完整的 URL 构建器。请注意,URI 的不同部分有不同的规则。有关更多分析,请参见此帖子 - McDowell
1
@McDowell 是的,我觉得我应该问一下如何让Java做像JavaScript的encodeURIComponent()那样的事情。我会查看你的库。 - John Farrelly
2个回答

43
尽管我认为@fge的回答是正确的,但由于我正在使用一个依赖于W3Schools文章中概述的编码方式的第三方网络服务,因此我遵循了Java equivalent to JavaScript's encodeURIComponent that produces identical output?中的答案。
public static String encodeURIComponent(String s) {
    String result;

    try {
        result = URLEncoder.encode(s, "UTF-8")
                .replaceAll("\\+", "%20")
                .replaceAll("\\%21", "!")
                .replaceAll("\\%27", "'")
                .replaceAll("\\%28", "(")
                .replaceAll("\\%29", ")")
                .replaceAll("\\%7E", "~");
    } catch (UnsupportedEncodingException e) {
        result = s;
    }

    return result;
}

4
你忘记了 & 符号,它对于解码 URL(GET 或 POST 方法均可)非常重要,因为这个符号分隔了请求中的键。 - Giorgos Fandomas
我不得不指出,w3schools并不是W3C。它们是非常不同的。 - Mike B

17

URI语法由RFC 3986定义(查询字符串的允许内容在第3.4节中定义)。Java的URI遵循此RFC,但在其Javadoc中提到了一些要点。

您会注意到,pchar语法规则由以下内容定义:

pchar = unreserved / pct-encoded / sub-delims / ":" / "@"

这意味着在查询字符串中使用@合法的

相信URI。它会执行正确的“合法”操作。

最后,如果您查看URLEncoder的Javadoc,您会发现它声明:

此类包含将String转换为application/x-www-form-urlencoded MIME格式的静态方法。

这与URI规范所定义的查询字符串不同。


我认为我应该问的问题是如何让Java像JavaScript的encodeURIComponent一样对URL进行编码,因为这是接收WebService所期望的方式:https://dev59.com/1XRB5IYBdhLWcg3weXSX - John Farrelly
从那时起,我开发了一个库,它可以处理URI模板(RFC 6570),甚至更加强大 ;) - fge
5
这很奇怪... URI 的 Javadocs 表示它遵循 RFC 2396,即使在 Java 8 中也是如此,而 RFC 2396 是从 1998 年发布的,并且自 2005 年以来已经被 RFC 3986 取代。 - arcuri82

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接