URI를 만들 때 호스트 이름이 유효하지 않은 것으로 선언 된 이유


17

JDK 1.8에서이 코드를 실행 :

try {
    System.out.println( new URI(null, null, "5-12-145-35_s-81", 443, null, null, null));
} catch (URISyntaxException e) {
    e.printStackTrace();
}

이 오류가 발생합니다. java.net.URISyntaxException: Illegal character in hostname at index 13: //5-12-145-35_s-81:443

URI 문자 유형에 따라 모든 호스트 이름 문자가 합법적이라고 생각하면이 오류는 어디에서 발생 합니까?


이 URL을 사용하면 : //5-12-145-35_s-81:443또는 /5-12-145-35_s-81:443오류가 사라집니다.


의견에서 RFC-2396 에 따르면 호스트 이름에 밑줄 문자를 사용할 수 없다는 것을 알고 있습니다.

여전히 남아있는 질문은 슬래시 또는 이중 슬래시로 시작하는 호스트 이름에 밑줄이 포함될 수있는 이유는 무엇입니까?


1
@ernest_k 스키마가 제공되지 않았으며 null입니다.
Eugen Covaci

여전히 URL에서 _를 원한다면 @ fg78nc 해결 방법이 효과가 있습니다. 호스트 이름이 유효하지 않고 필드를 만들지 않기 때문에 /를 사용하지 마십시오
salesh

3
RFC-2396 섹션 3.2.2를 참조하십시오 . URI의 호스트 이름은 -점으로 구분 된 하나 이상의 영숫자 + 그룹 일 수 있습니다.
Mark

@MarkRotteveel java.net.URI의 최신 사양과 최신되지 않습니다
fg78nc

@ fg78nc RFC-3986이 완화했지만 "DNS에서 조회 용으로 등록 된 이름은 [RFC1034] 3.5 항 및 [RFC1123] 2.1 항에 정의 된 구문을 사용합니다."라고 언급합니다. 이는 기본적으로 RFC-2396 섹션 3.2.2의 구문입니다.
마크 Rotteveel

답변:


8

호스트 이름은 다음 구문과 일치해야합니다.

hostname      = domainlabel [ "." ] | 1*( domainlabel "." ) toplabel [ "." ]
domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
toplabel      = alpha | alpha *( alphanum | "-" ) alphanum

당신이 볼 수 있듯이, 단지 .-, 허용 _되지 않습니다.


그런 다음 //5-12-145-35_s-81:443허용되지만 호스트 이름 에는 해당되지 않습니다 .

어떻게 진행되는지 확인하려면 :

URI uriBadHost = URI.create("//5-12-145-35_s-81:443");
System.out.println("uri = " + uriBadHost);
System.out.println("  authority = " + uriBadHost.getAuthority());
System.out.println("  host = " + uriBadHost.getHost());
System.out.println("  port = " + uriBadHost.getPort());
URI uriGoodHost = URI.create("//example.com:443");
System.out.println("uri = " + uriGoodHost);
System.out.println("  authority = " + uriGoodHost.getAuthority());
System.out.println("  host = " + uriGoodHost.getHost());
System.out.println("  port = " + uriGoodHost.getPort());

산출

uri = //5-12-145-35_s-81:443
  authority = 5-12-145-35_s-81:443
  host = null
  port = -1
uri = //example.com:443
  authority = example.com:443
  host = example.com
  port = 443

보다시피, authority호스트 이름이 유효한 경우 hostport구문 분석되지만 유효하지 않은 경우 authority자유 형식 텍스트로 처리되며 더 이상 구문 분석되지 않습니다.


최신 정보

의견에서 :

System.out.println( new URI(null, null, "/5-12-145-35_s-81", 443, null, null, null))출력 : /// 5-12-145-35_s-81 : 443. 호스트 이름으로 제공하고 있습니다

URI호출 하는 생성자는 편리한 메소드이며 전체 URI 문자열을 간단하게 빌드 한 다음 구문 분석합니다.

합격 "5-12-145-35_s-81", 443이됩니다 //5-12-145-35_s-81:443.
합격 "/5-12-145-35_s-81", 443이됩니다 ///5-12-145-35_s-81:443.

첫 번째로 호스트포트 이며 구문 분석에 실패합니다.
두 번째로 권한 부분은 비어 /5-12-145-35_s-81:443있으며 경로 입니다.

URI uri1 = new URI(null, null, "/5-12-145-35_s-81", 443, null, null, null);
System.out.println("uri = " + uri1);
System.out.println("  authority = " + uri1.getAuthority());
System.out.println("  host = " + uri1.getHost());
System.out.println("  port = " + uri1.getPort());
System.out.println("  path = " + uri1.getPath());

산출

uri = ///5-12-145-35_s-81:443
  authority = null
  host = null
  port = -1
  path = /5-12-145-35_s-81:443

이제는 이해하지만, 왜 말해 봅시다 /a_b. 유일한 차이점은 이것이 상대적이 아니라 절대적이라는 것입니다
Eugen Covaci

System.out.println( new URI(null, null, "/5-12-145-35_s-81", 443, null, null, null))출력 : ///5-12-145-35_s-81:443. 호스트 이름으로 제공하고 있습니다.
Eugen Covaci

이 동작 (호스트 이름이 절대 인 경우)은 이상하게도 이상합니다. URI의 생성자는 호스트 이름과 포트를 제공하고 결과 URI에는 경로가 하나만 없습니다.
Eugen Covaci

5

밑줄이 호스트 이름에 유효한 문자가 아니기 때문에 버그는 Java가 아니라 호스트 이름을 지정할 때 발생합니다. 널리 사용되지는 않지만 Java는 이러한 호스트 이름을 처리하지 않습니다.


이것은 /5-12-145-35_s-81:443합법적입니다.
Eugen Covaci

2

밑줄은 URI에서 지원되지 않습니다.

호스트 이름에는 밑줄 문자 (_)와 같은 다른 문자가 포함될 수 없지만 다른 DNS 이름에는 밑줄이 포함될 수 있습니다. [5] [6] 이 제한은 RFC 2181, 섹션 11에 의해 해제되었습니다. DomainKeys 및 서비스 레코드와 같은 시스템은 특수 문자가 호스트 이름과 혼동되지 않도록하기 위해 밑줄을 사용합니다. 예를 들어, _http._sctp.www.example.com은 example.com 도메인에서 SCTP 가능 웹 서버 호스트 (www)에 대한 서비스 포인터를 지정합니다. 표준에도 불구하고 Chrome, Firefox, Internet Explorer, Edge 및 Safari는 호스트 이름에 밑줄을 허용하지만 호스트 이름의 일부에 밑줄 문자가 포함되어 있으면 IE의 쿠키가 올바르게 작동하지 않습니다

위키 백과

Javadocs에서 :

public URI (String str) throws URISyntaxException Throws : URISyntaxException-지정된 캐릭터 라인이 RFC 2396를 위반했을 경우, 위의 편차에 의해 증대 된

자바 독

(해키) 해결책 :

    URI url = URI.create("https://5-12-145-35_s-8:8080");

    System.out.println(url.getHost()) // null

    if (url.getHost() == null) {
        final Field hostField = URI.class.getDeclaredField("host");
        hostField.setAccessible(true);
        hostField.set(url, "5-12-145-35_s-81");
    }
    System.out.println(url.getHost()); // 5-12-145-35_s-81

이것은 JDK 버그 로보고되었습니다.


1
와우, 그것은 해키 솔루션입니다. 내부 클래스에 대해 내부자를 가정하고 리플렉션을 사용하여 직접 액세스하므로 향후에 중단 될 수 있다고 진술 할 수 있습니다. 따라서 구현은 모든 Java 릴리스에서 변경 될 수 있으며이 경우 중단 될 수 있습니다. 그래도 솔루션 을 제공 하기 위해 +1 .
Zabuzard

내가하지 않은이 해결 방법을 넣고 싶을 때 Zabuza가 언급 한 것과 관련하여 문제가 있습니다. + 규칙을 지키기 시작하면 모든 것이 천천히 붕괴되기 시작합니다. 이것이 처음부터 작동하지 않는 좋은 이유가 있습니다.
salesh

@salesh 그리고 그 좋은 이유는 무엇입니까?
fg78nc

"DomainKeys 및 서비스 레코드와 같은 시스템은 밑줄을 사용하여 특수 문자가 호스트 이름과 혼동되지 않도록합니다." wikipedia 여기에 정답이 있습니다 quora
salesh

1
그렇게하면 null호스트가됩니다.
fg78nc
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.