Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เหตุใด URI.join จึงขัดกับสัญชาตญาณมาก

เราเพิ่งมาถึงเหตุการณ์สำคัญที่ฮันนี่แบดเจอร์ หน้าการขายของเราไม่ได้เป็นส่วนหนึ่งของแอป 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

วิธีการผสานทำสองสิ่ง:

  1. มันแปลงสตริงของคุณเช่น "หน้า" เป็นวัตถุ URI ที่เกี่ยวข้อง
  2. พยายามแก้ไข 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) องค์ประกอบเส้นทางของการอ้างอิงถูกผนวกเข้ากับสตริงบัฟเฟอร์

มาเล่นกันเถอะ:

  1. คัดลอกทุกอย่างยกเว้นส่วนสุดท้ายของ URL ที่สมบูรณ์ นั่นทำให้ฉัน "https://www.honeybadger.io/"
  2. ผนวกพาธสัมพัทธ์ต่อท้ายส่งผลให้ "https://www.honeybadger.io/change"

โลกกลับมามีเหตุผลอีกครั้ง!

บทสรุป

ขณะที่ URI.join สามารถใช้เพื่อสร้าง URL จากส่วนย่อยของเส้นทางต่างๆ ซึ่งไม่ใช่สิ่งที่ออกแบบมาเพื่อทำจริงๆ ได้รับการออกแบบมาเพื่อทำสิ่งที่ซับซ้อนกว่าเล็กน้อย:รวม URI แบบเรียกซ้ำตามมาตรฐานที่ระบุใน RFC

สำหรับโครงการส่วนตัวของฉัน — การสร้าง URL เพื่อใช้ในการเปลี่ยนเส้นทางไปยังหน้าการขายใหม่ของเรา — ฉันแค่ใช้ Array#join แทน :)

แก้ไข 8/12/2559: หลังจากเผยแพร่บทความนี้ ฉันได้รับทวีตสองสามทวีตที่แนะนำให้ฉันใช้ File.join เพื่อจุดประสงค์นี้. สิ่งนี้มีประโยชน์ในการหลีกเลี่ยงการทับซ้อน กล่าวคือ /my//path แต่จะพังในระบบปฏิบัติการเช่น Windows โดยที่ตัวคั่นพาธไม่ใช่ฟอร์เวิร์ดสแลช