ในการออกแบบ RESTful Web Service โดยใช้ HATEOAS ข้อดีข้อเสียของการแสดงลิงก์เป็น URL แบบสมบูรณ์คืออะไร (" http: // server: port / application / customers / 1234 ") เทียบกับ just the path ("/ application / ลูกค้า / 1234 ")?
ในการออกแบบ RESTful Web Service โดยใช้ HATEOAS ข้อดีข้อเสียของการแสดงลิงก์เป็น URL แบบสมบูรณ์คืออะไร (" http: // server: port / application / customers / 1234 ") เทียบกับ just the path ("/ application / ลูกค้า / 1234 ")?
คำตอบ:
มีแนวคิดที่คลุมเครือเล็กน้อยเมื่อมีคนพูดว่า "URI ที่เกี่ยวข้อง"
ตามคำจำกัดความของ RFC3986 URI ทั่วไปประกอบด้วย:
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
สิ่งที่ยุ่งยากคือเมื่อละเว้นโครงร่างและอำนาจส่วน "เส้นทาง" เองอาจเป็นได้ทั้งเส้นทางสัมบูรณ์ (ขึ้นต้นด้วย/
) หรือเส้นทางสัมพัทธ์ "ไม่มีราก" ตัวอย่าง:
"http://example.com:8042/over/there?name=ferret"
/over/there
here
หรือ./here
หรือ../here
หรือ ฯลฯดังนั้นถ้าคำถามคือ "ไม่ว่าจะเป็นเซิร์ฟเวอร์ควรผลิตทางญาติในการตอบสนองการพักผ่อน" คำตอบคือ "ไม่" และเหตุผลรายละเอียดได้ที่นี่ ฉันคิดว่าคนส่วนใหญ่ (รวมฉัน) ที่ต่อต้าน "URI สัมพัทธ์" นั้นต่อต้าน "เส้นทางสัมพัทธ์" จริงๆ
และในทางปฏิบัติเฟรมเวิร์ก MVC ฝั่งเซิร์ฟเวอร์ส่วนใหญ่สามารถสร้างURI สัมพัทธ์ด้วยพา ธ สัมบูรณ์เช่น/absolute/path/to/the/controller
และคำถามจะกลายเป็น "ว่าการติดตั้งเซิร์ฟเวอร์ควรนำscheme://hostname:port
หน้าเส้นทางสัมบูรณ์" หรือไม่ ชอบคำถามของ OP ฉันไม่ค่อยแน่ใจเกี่ยวกับเรื่องนี้
ในแง่หนึ่งฉันยังคิดว่าเซิร์ฟเวอร์ที่ส่งคืน uri แบบเต็มแนะนำให้ใช้ อย่างไรก็ตามเซิร์ฟเวอร์ไม่hostname:port
ควรฮาร์ดโค้ดสิ่งที่อยู่ในซอร์สโค้ดเช่นนี้ (มิฉะนั้นฉันอยากจะกลับไปใช้ uri สัมพัทธ์ด้วยพา ธ สัมบูรณ์) โซลูชันคือฝั่งเซิร์ฟเวอร์รับคำนำหน้านั้นจากส่วนหัว "โฮสต์" ของคำขอ HTTP เสมอ ไม่แน่ใจว่าจะใช้ได้กับทุกสถานการณ์หรือไม่
ในทางกลับกันดูเหมือนว่าลูกค้าจะไม่สามารถเชื่อมต่อกับhttp://example.com:8042
เส้นทางสัมบูรณ์ได้ ท้ายที่สุดไคลเอนต์รู้โครงร่างและชื่อโดเมนนั้นอยู่แล้วเมื่อส่งคำขอไปยังเซิร์ฟเวอร์ใช่ไหม
ทั้งหมดในทุกฉันจะบอกว่าขอแนะนำให้ใช้แน่นอน URI อาจจะเป็นทางเลือกที่จะ URI สัมพันธ์กับเส้นทางที่แน่นอนไม่เคยใช้เส้นทางสัมพัทธ์
ขึ้นอยู่กับว่าใครเป็นคนเขียนโค้ดไคลเอ็นต์ หากคุณกำลังเขียนไคลเอนต์และเซิร์ฟเวอร์จะไม่สร้างความแตกต่างมากนัก คุณอาจเจ็บปวดจากการสร้าง URL บนไคลเอนต์หรือบนเซิร์ฟเวอร์
อย่างไรก็ตามหากคุณกำลังสร้างเซิร์ฟเวอร์และคาดหวังให้คนอื่นเขียนโค้ดไคลเอ็นต์พวกเขาจะรักคุณมากขึ้นหากคุณให้ URI ที่สมบูรณ์ การแก้ไข URI แบบสัมพัทธ์อาจเป็นเรื่องยุ่งยากเล็กน้อย ก่อนอื่นคุณจะแก้ไขอย่างไรขึ้นอยู่กับประเภทสื่อที่ส่งคืน Html มีแท็กฐาน Xml สามารถมี xml: แท็กฐานในทุกองค์ประกอบที่ซ้อนกันฟีด Atom อาจมีฐานในฟีดและฐานอื่นในเนื้อหา หากคุณไม่ได้ให้ข้อมูลที่ชัดเจนเกี่ยวกับ URI พื้นฐานแก่ลูกค้าของคุณพวกเขาจะต้องได้รับ URI พื้นฐานจาก URI คำขอหรืออาจมาจากส่วนหัว Content-Location! และระวังการเฉือนต่อท้าย URI พื้นฐานถูกกำหนดโดยละเว้นอักขระทั้งหมดทางด้านขวาของเครื่องหมายทับสุดท้าย ซึ่งหมายความว่าตอนนี้เครื่องหมายทับมีความสำคัญมากเมื่อแก้ไข URI สัมพัทธ์
ปัญหาอื่น ๆ ที่ต้องมีการกล่าวถึงเล็กน้อยคือขนาดเอกสาร หากคุณส่งคืนรายการจำนวนมากโดยที่แต่ละรายการอาจมีลิงก์หลายลิงก์การใช้ URL ที่สมบูรณ์สามารถเพิ่มไบต์จำนวนมากให้กับเอนทิตีของคุณได้หากคุณไม่บีบอัดเอนทิตี นี่เป็นปัญหาที่สมบูรณ์แบบและคุณต้องตัดสินใจว่ามีความสำคัญเป็นรายกรณีไปหรือไม่
ข้อแตกต่างที่แท้จริงเพียงอย่างเดียวก็คือมันง่ายกว่าสำหรับลูกค้าหากพวกเขาใช้ URI แบบสัมบูรณ์แทนที่จะต้องสร้างจากเวอร์ชันสัมพัทธ์ แน่นอนว่าความแตกต่างนั้นเพียงพอที่จะทำให้ฉันตัดสินใจทำเวอร์ชันสัมบูรณ์
เมื่อแอปพลิเคชันของคุณปรับขนาดคุณอาจต้องการทำโหลดบาลานซ์ล้มเหลว ฯลฯ หากคุณส่งคืน URI แบบสัมบูรณ์แอปฝั่งไคลเอ็นต์ของคุณจะทำตามการกำหนดค่าเซิร์ฟเวอร์
/xxx/yyy...
) และไม่ใช่ความหมาย URI ที่มีคุณสมบัติครบถ้วน (เช่นhttp://api.example.com/xxx/yyy...
)
การใช้Trichotomy ของ RayLouองค์กรของฉันเลือกที่จะชื่นชอบ (2) เหตุผลหลักคือเพื่อหลีกเลี่ยงการโจมตี XSS (Cross-Site Scripting) ปัญหาคือหากผู้โจมตีสามารถแทรกรูท URL ของตนเองลงในการตอบกลับที่กลับมาจากเซิร์ฟเวอร์คำขอของผู้ใช้ที่ตามมา (เช่นคำขอรับรองความถูกต้องด้วยชื่อผู้ใช้และรหัสผ่าน) จะถูกส่งต่อไปยังเซิร์ฟเวอร์ของผู้โจมตีเอง *
บางคนมีปัญหาเรื่องความสามารถในการเปลี่ยนเส้นทางการร้องขอไปยังเซิร์ฟเวอร์อื่นสำหรับการทำโหลดบาลานซ์ แต่ (แม้ว่านั่นจะไม่ใช่ความเชี่ยวชาญของฉัน) ฉันจะเดิมพันว่ามีวิธีที่ดีกว่าในการเปิดใช้งานการจัดสรรภาระงานโดยไม่ต้องเปลี่ยนเส้นทางไคลเอ็นต์ไปยังเซิร์ฟเวอร์อื่นอย่างชัดเจน เจ้าภาพ
* โปรดแจ้งให้เราทราบหากมีข้อบกพร่องในการให้เหตุผลบรรทัดนี้ แน่นอนว่าเป้าหมายไม่ใช่เพื่อป้องกันการโจมตีทั้งหมด แต่ต้องมีการโจมตีอย่างน้อยหนึ่งช่องทาง
คุณควรใช้ URL แบบเต็มเสมอ ทำหน้าที่เป็นตัวระบุเฉพาะสำหรับทรัพยากรเนื่องจาก URL ทั้งหมดจำเป็นต้องไม่ซ้ำกัน
ฉันจะเถียงว่าคุณควรจะเสมอต้นเสมอปลาย เนื่องจากส่วนหัวตำแหน่ง HTTP ต้องการ URL แบบเต็มตามข้อกำหนดของ HTTP URL แบบเต็มจะถูกส่งกลับในส่วนหัวตำแหน่งไปยังไคลเอ็นต์เมื่อสร้างทรัพยากรใหม่ เป็นเรื่องแปลกสำหรับคุณที่จะระบุ URL แบบเต็มในส่วนหัวสถานที่แล้วตามด้วย URI สัมพัทธ์ในลิงก์ภายในเนื้อหาการตอบกลับของคุณ
Location
ส่วนหัวที่ระบุคือ URI แบบสัมบูรณ์ซึ่งไม่มีโครงร่าง URI หรือตำแหน่งเครือข่ายของเซิร์ฟเวอร์ แม้ว่าลิงก์และ ID มักจะรวมกัน แต่ก็ไม่ใช่สิ่งเดียวกัน แต่ก่อนหน้านี้มีบริบท แต่อย่างหลังไม่มี
การพิจารณาที่สำคัญในผลลัพธ์ API ขนาดใหญ่คือค่าใช้จ่ายของเครือข่ายเพิ่มเติมในการรวม URI แบบเต็มซ้ำ ๆ เชื่อหรือไม่ว่า gzip ไม่สามารถแก้ปัญหานี้ได้ทั้งหมด (ไม่แน่ใจว่าทำไม) เราตกใจมากที่ URI เต็มพื้นที่ใช้เวลาเท่าใดเมื่อมีลิงก์หลายร้อยลิงก์รวมอยู่ในผลลัพธ์
ข้อเสียเปรียบอย่างหนึ่งของการใช้ URI แบบสัมบูรณ์คือไม่สามารถพร็อกซีได้
เอาคืน ... ไม่จริง. คุณควรไปหา URL แบบเต็มรวมทั้งโดเมน
เกี่ยวกับข้อดีฉันเห็นว่าการลดจำนวนไบต์ที่จะส่งโดยเสียค่าใช้จ่ายในการจัดการเพิ่มเติมที่ไคลเอนต์ต้องการสำหรับเส้นทาง (สัมบูรณ์) หากคุณหมดหวังที่จะบันทึกทุกไบต์แม้ว่าจะพยายามเข้ารหัสเนื้อหาเป็น gzip แล้วก็ตามการใช้ส่วนหัวการแคชอย่างเหมาะสมการใช้ etags และคำขอตามเงื่อนไขบนไคลเอนต์สิ่งนี้อาจจำเป็นในท้ายที่สุด แต่ฉันคาดหวังว่าจะได้รับผลตอบแทนที่สูงกว่ามาก ความพยายามของคุณ
เกี่ยวกับข้อเสียฉันเห็นว่าสูญเสียการควบคุมเกี่ยวกับวิธีที่คุณสามารถกำหนดทิศทางการไหลของไคลเอนต์ระหว่างทรัพยากรในอนาคต (การทำโหลดบาลานซ์, การทดสอบ A / B, ... ) และฉันคิดว่าเป็นแนวทางปฏิบัติที่ไม่ดีเกี่ยวกับการจัดการเว็บ API URL ที่คุณระบุจะไม่ทึบแสงสำหรับไคลเอ็นต์อีกต่อไป (ดู Tim Berners-Lee Axioms of Web Architecture เกี่ยวกับความทึบ URI ) ในท้ายที่สุดคุณต้องรับผิดชอบในการทำให้ลูกค้าพึงพอใจเกี่ยวกับการใช้งาน API ของคุณอย่างสร้างสรรค์แม้ว่าจะเกี่ยวข้องกับโครงสร้างของพื้นที่ URL ของคุณก็ตาม หากคุณจำเป็นต้องอนุญาตให้มีการปรับเปลี่ยน URL ที่กำหนดไว้อย่างชัดเจนพิจารณาการใช้งานของแม่แบบ URIที่ใช้ในHypertext ประยุกต์ใช้ภาษา