เราเพิ่งมาถึงเหตุการณ์สำคัญที่ฮันนี่แบดเจอร์ หน้าการขายของเราไม่ได้เป็นส่วนหนึ่งของแอป Rails หลักของเราอีกต่อไป มันอยู่ในรายการความปรารถนาของฉันมาหลายปีแล้ว แต่ไม่ได้มีความสำคัญสูงสุดอย่างแน่นอน
ส่วนหนึ่งของการย้ายข้อมูลนี้ ฉันพบว่าตัวเองใช้ URI.join
เพื่อสร้างลิงก์เปลี่ยนเส้นทางโดยเฉพาะ แต่ฉันพบปัญหาอย่างรวดเร็ว URI.join
ไม่ได้ประพฤติตามที่ฉันคาดไว้
ฉันคาดว่ามันจะนำเศษส่วนของเส้นทางมามัดรวมกันดังนี้:
# This is what I was expecting. It didn't happen.
URI.join("https://www.honeybadger.io", "plans", "change")
=> "https://www.honeybadger.io/plans/change"
สิ่งที่ join
วิธีการทำเป็นคนแปลกหน้ามาก มันทิ้งเศษเส้นทางของฉันชิ้นหนึ่ง ใช้ชิ้นสุดท้าย "เปลี่ยน"
# This is what happened.
URI.join("https://www.honeybadger.io", "plans", "change")
=> "https://www.honeybadger.io/change"
แล้วทำไมมันทำงานแบบนี้ล่ะ
ความเข้าใจผิด
ปรากฎว่าฉันคาดหวัง URI.join
ให้ทำงานคล้ายกับ Array#join
. รุ่นพิเศษ นำส่วนย่อยของ URL มารวมกันเพื่อสร้าง URL ทั้งหมด
นั่นไม่ใช่สิ่งที่มันทำ เซอร์ไพรส์สุดๆ
ถ้าเราดูที่ join
โค้ดของ method เราเห็นว่ามันแค่วนซ้ำอาร์กิวเมนต์ทั้งหมดแล้วเรียก merge
ในแต่ละ.
# File uri/rfc2396_parser.rb, line 236
def join(*uris)
uris[0] = convert_to_uri(uris[0])
uris.inject :merge
end
วิธีการผสานทำสองสิ่ง:
- มันแปลงสตริงของคุณเช่น "หน้า" เป็นวัตถุ URI ที่เกี่ยวข้อง
- พยายามแก้ไข URI ที่สัมพันธ์กับ URI ฐาน โดยดำเนินการในลักษณะเดียวกับที่ระบุไว้ใน RFC2396 มาตรา 5.2
เยี่ยมมาก แต่อธิบายพฤติกรรมที่ไม่คาดคิดที่ฉันพูดถึงก่อนหน้านี้ได้อย่างไร
URI.join("https://www.honeybadger.io", "plans", "change")
=> "https://www.honeybadger.io/change"
ก้าวผ่านมันไป รหัสข้างต้นเทียบเท่ากับ:
URI.parse("https://www.honeybadger.io/plans").merge("change")
โค้ดด้านบนพยายามแก้ไข URI ที่เกี่ยวข้อง "เปลี่ยน" กับ URI แบบสัมบูรณ์ "https://www.honeybadger.io/plans"
ในการดำเนินการนี้ เป็นไปตาม RFC2396 มาตรา 5.2.6 ซึ่งระบุว่า:
a) ทั้งหมดยกเว้นส่วนสุดท้ายขององค์ประกอบพาธของ URI ฐานถูกคัดลอกไปยังบัฟเฟอร์ กล่าวอีกนัยหนึ่ง อักขระใดๆ หลังเครื่องหมายทับ (ขวาสุด) ตัวสุดท้าย (ถ้ามี) จะถูกยกเว้น
b) องค์ประกอบเส้นทางของการอ้างอิงถูกผนวกเข้ากับสตริงบัฟเฟอร์
มาเล่นกันเถอะ:
- คัดลอกทุกอย่างยกเว้นส่วนสุดท้ายของ URL ที่สมบูรณ์ นั่นทำให้ฉัน
"https://www.honeybadger.io/"
- ผนวกพาธสัมพัทธ์ต่อท้ายส่งผลให้
"https://www.honeybadger.io/change"
โลกกลับมามีเหตุผลอีกครั้ง!
บทสรุป
ขณะที่ URI.join
สามารถใช้เพื่อสร้าง URL จากส่วนย่อยของเส้นทางต่างๆ ซึ่งไม่ใช่สิ่งที่ออกแบบมาเพื่อทำจริงๆ ได้รับการออกแบบมาเพื่อทำสิ่งที่ซับซ้อนกว่าเล็กน้อย:รวม URI แบบเรียกซ้ำตามมาตรฐานที่ระบุใน RFC
สำหรับโครงการส่วนตัวของฉัน — การสร้าง URL เพื่อใช้ในการเปลี่ยนเส้นทางไปยังหน้าการขายใหม่ของเรา — ฉันแค่ใช้ Array#join แทน :)
แก้ไข 8/12/2559: หลังจากเผยแพร่บทความนี้ ฉันได้รับทวีตสองสามทวีตที่แนะนำให้ฉันใช้ File.join
เพื่อจุดประสงค์นี้. สิ่งนี้มีประโยชน์ในการหลีกเลี่ยงการทับซ้อน กล่าวคือ /my//path
แต่จะพังในระบบปฏิบัติการเช่น Windows โดยที่ตัวคั่นพาธไม่ใช่ฟอร์เวิร์ดสแลช