ทำไมชื่อโฮสต์ถึงประกาศไม่ถูกต้องเมื่อสร้าง 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

ไม่ข้อผิดพลาดนี้มาจากไหนพิจารณาทุกตัวอักษรชื่อโฮสต์ดูเหมือน Legit ตามประเภทของตัวอักษร URI ?


ถ้าฉันใช้ URL เหล่านี้: //5-12-145-35_s-81:443หรือ/5-12-145-35_s-81:443ข้อผิดพลาดหายไป


จากความคิดเห็นฉันเข้าใจว่าตามRFC-2396ชื่อโฮสต์ไม่สามารถมีอักขระขีดล่างใด ๆ

คำถามที่ยังคงอยู่คือทำไมชื่อโฮสต์ที่ขึ้นต้นด้วยเครื่องหมายทับหรือเครื่องหมายทับสองได้รับอนุญาตให้มีขีดล่าง?


1
@ernest_k รูปแบบไม่ได้รับเป็นโมฆะ
— Eugen Covaci

หากคุณยังต้องการ _ ใน url @ fg78nc วิธีแก้ปัญหาจะทำงานให้คุณ อย่าใช้ / เพราะชื่อโฮสต์จะไม่ถูกต้องและจะไม่สร้างฟิลด์
— salesh

3
ดูRFC-2396ส่วน 3.2.2 ชื่อโฮสต์ใน URI สามารถเป็นตัวอักษรและตัวเลขอย่างน้อยหนึ่งกลุ่ม-โดยคั่นด้วยจุด
— Mark Rotteveel

@MarkRotteveel java.net.URI ไม่ทันสมัยพร้อมข้อมูลจำเพาะล่าสุด
— fg78nc

@ fg78nc แม้ว่า RFC-3986 จะผ่อนคลาย แต่ก็ยังกล่าวว่า"ชื่อที่ลงทะเบียนไว้สำหรับการค้นหาใน DNS ใช้ไวยากรณ์ที่กำหนดไว้ในส่วน 3.5 ของ [RFC1034] และมาตรา 2.1 ของ [RFC1123] และนั่นก็คือไวยากรณ์ของ RFC-2396 ส่วน 3.2.2
— Mark 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มีชื่อโฮสต์ที่ถูกต้องhostและportมีการแยกวิเคราะห์ แต่เมื่อไม่ถูกต้องauthorityจะถือว่าเป็นข้อความอิสระและไม่แยกวิเคราะห์เพิ่มเติม


UPDATE

จากความคิดเห็น:

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

ไม่รองรับขีดล่างใน URIs

แม้ว่าชื่อโฮสต์อาจไม่มีอักขระอื่นเช่นอักขระขีดล่าง (_) แต่ชื่อ DNS อื่นอาจมีเครื่องหมายขีดล่าง [5] [6] ข้อ จำกัด นี้ถูกยกขึ้นโดย RFC 2181 ส่วนที่ 11 ระบบเช่น DomainKeys และบันทึกการใช้บริการใช้ขีดเส้นใต้เป็นวิธีการเพื่อรับรองว่าอักขระพิเศษของพวกเขาจะไม่สับสนกับชื่อโฮสต์ ตัวอย่างเช่น _http._sctp.www.example.com ระบุตัวชี้บริการสำหรับโฮสต์เว็บเซิร์ฟเวอร์ที่มีความสามารถ SCTP (www) ในโดเมน example.com แม้จะมีมาตรฐาน, Chrome, Firefox, Internet Explorer, Edge และ Safari อนุญาตให้มีการขีดเส้นใต้ในชื่อโฮสต์แม้ว่าคุกกี้ใน IE จะทำงานไม่ถูกต้องหากส่วนใดส่วนหนึ่งของชื่อโฮสต์มีอักขระขีดล่าง

วิกิพีเดีย

จาก Javadocs:

URI สาธารณะ (String STR) พ่น URISyntaxException พ่น: URISyntaxException - หากสตริงที่กำหนดละเมิด RFC 2396 ตามที่ได้รับการเสริมโดยการเบี่ยงเบนด้านบน

Javadocs

โซลูชั่น (Hacky):

    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 และอะไรคือเหตุผลที่ดี
— fg78nc

"ระบบต่าง ๆ เช่น DomainKeys และระเบียนบริการใช้ขีดเส้นใต้เป็นวิธีการที่รับประกันว่าอักขระพิเศษของพวกเขาจะไม่สับสนกับชื่อโฮสต์" วิกิพีเดียและมีคำตอบที่ดีที่นี่quora
— salesh

1
ถ้าคุณทำเช่นนั้นคุณจะได้nullเป็นเจ้าภาพ
— fg78nc
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.