java.net.URI获取带下划线的主机

时间:2015-02-17 18:11:29

标签: java http amazon-s3 uri

我对该方法有一种奇怪的行为:

import java.net.URI

    URI url = new URI("https://pmi_artifacts_prod.s3.amazonaws.com");
    System.out.println(url.getHost()); /returns NULL
    URI url2 = new URI("https://s3.amazonaws.com");
    System.out.println(url2.getHost());  //returns s3.amazonaws.com

`

我希望首先url.getHost()成为pmi_artifacts_prod.s3.amazonaws.com,但它会给我NULL。事实证明,问题在于域名中的下划线,这是一个已知的错误,但仍然可以做什么,因为我需要完全使用这个主机?

4 个答案:

答案 0 :(得分:2)

https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_hostnames

public static void main(String...a) throws URISyntaxException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
    URI url = new URI("https://pmi_artifacts_prod.s3.amazonaws.com");
    System.out.println(url.getHost()); //NULL


    URI uriObj = new URI("https://pmi_artifacts_prod.s3.amazonaws.com");
    if (uriObj.getHost() == null) {
        final Field hostField = URI.class.getDeclaredField("host");
        hostField.setAccessible(true);
        hostField.set(uriObj, "pmi_artifacts_prod.s3.amazonaws.com");
    }
    System.out.println(uriObj.getHost()); //pmi_artifacts_prod.s3.amazonaws.com


    URI url2 = new URI("https://s3.amazonaws.com");
    System.out.println(url2.getHost());  //s3.amazonaws.com
}

答案 1 :(得分:1)

通过修补可以将下划线支持添加到URI中:

public static void main(String[] args) throws Exception {
    patchUriField(35184372088832L, "L_DASH");
    patchUriField(2147483648L, "H_DASH");

    URI s = URI.create("http://my_favorite_host:3892");
    // prints "my_favorite_host"
    System.out.println(s.getHost());
}

private static void patchUriField(String methodName, String fieldName)
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, NoSuchFieldException {
        Field field = URI.class.getDeclaredField(fieldName);

        Field modifiers = Field.class.getDeclaredField("modifiers");
        modifiers.setAccessible(true);
        modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);

        field.setAccessible(true);
        field.setLong(null, maskValue);
}

答案 2 :(得分:1)

注意虽然

new URI("https://pmi_artifacts_prod.s3.amazonaws.com");

不会抛出,@Vurtatoo 提供的解决方法适用于这种情况,它无法处理诸如 https://a_b?c={1}

我也发现了

new URI("https://a_b?c={1}")

会抛出但是

new URI("https://a_b?c=1")

不会。

不知道为什么会这样,但我的结论是我们不应该对 Java URI 类的实现细节做出任何假设。如果您必须使用 Java URI,最好分叉源代码并进行所需的更改。

答案 3 :(得分:-1)

不,结果绝对正确。请仔细阅读url.getHost()

的文档

Java文档说  :

The host component of a URI, if defined, will have one of the following forms: 

    A domain name consisting of one or more labels separated by period characters ('.'), optionally followed by a period character. Each label consists of alphanum characters as well as hyphen characters ('-'), though hyphens never occur as the first or last characters in a label. The rightmost label of a domain name consisting of two or more labels, begins with an alpha character. 

    A dotted-quad IPv4 address of the form digit+.digit+.digit+.digit+, where no digit sequence is longer than three characters and no sequence has a value larger than 255. 

    An IPv6 address enclosed in square brackets ('[' and ']') and consisting of hexadecimal digits, colon characters (':'), and possibly an embedded IPv4 address. The full syntax of IPv6 addresses is specified in RFC 2373: IPv6 Addressing Architecture. 

    The host component of a URI cannot contain escaped octets, hence this method does not perform any decoding.
    Returns:
    The host component of this URI, or null if the host is undefined

要添加到这个答案,如果使用eclipse请跳转到方法定义(按f3),您将得到答案。