java.net.URI 获取带下划线的主机
java.net.URI get host with underscores
我发现该方法有一个奇怪的行为:
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。原来问题出在域名中的下划线,这是一个已知的错误,但仍然可以做些什么,因为我需要准确地使用这个主机?
错误不在 Java 中,而是在命名主机中,因为下划线 不是 主机名中的有效字符。尽管被广泛错误地使用,Java 拒绝处理此类主机名。
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
}
可以通过修补将下划线支持直接添加到 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(Long maskValue, 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);
}
注意虽然
new URI("https://pmi_artifacts_prod.s3.amazonaws.com");
不会抛出并且@Vurtatoo 提供的解决方法适用于这种情况,它无法处理 url 例如 https://a_b?c={1}
我也发现
new URI("https://a_b?c={1}")
会抛出但是
new URI("https://a_b?c=1")
不会。
不确定为什么会这样,但我的收获是我们不应该对 Java URI class 的实现细节做出任何假设。如果您必须使用 Java 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。原来问题出在域名中的下划线,这是一个已知的错误,但仍然可以做些什么,因为我需要准确地使用这个主机?
错误不在 Java 中,而是在命名主机中,因为下划线 不是 主机名中的有效字符。尽管被广泛错误地使用,Java 拒绝处理此类主机名。
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
}
可以通过修补将下划线支持直接添加到 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(Long maskValue, 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);
}
注意虽然
new URI("https://pmi_artifacts_prod.s3.amazonaws.com");
不会抛出并且@Vurtatoo 提供的解决方法适用于这种情况,它无法处理 url 例如 https://a_b?c={1}
我也发现
new URI("https://a_b?c={1}")
会抛出但是
new URI("https://a_b?c=1")
不会。
不确定为什么会这样,但我的收获是我们不应该对 Java URI class 的实现细节做出任何假设。如果您必须使用 Java URI,最好分叉源代码并进行所需的更改。