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

เข้าใจ URI.join: หลุมที่พบบ่อยและวิธีใช้ให้ถูกต้อง

เราถึง milestone ที่ Honeybadger sales pages ไม่ใช่ส่วนหนึ่งของ main Rails app แล้ว อยากทำมาหลายปี แต่ไม่ใช่ top priority

ระหว่าง migration ผมใช้ URI.join สร้าง redirect links แต่มันไม่ behave ตามที่คาด

คาดว่า มันรับ path fragments มา string together เหมือนนี้:

# นี่คือสิ่งที่คาดหวัง ไม่ได้เกิดขึ้น
URI.join("https://www.honeybadger.io", "plans", "change")
# => "https://www.honeybadger.io/plans/change"

สิ่งที่ join ทำจริงแปลกกว่า มัน drop path fragment หนึ่ง ใช้แค่ตัวสุดท้าย "change"

# สิ่งที่เกิดขึ้นจริง
URI.join("https://www.honeybadger.io", "plans", "change")
# => "https://www.honeybadger.io/change"

ทำไมมันทำงานแบบนี้?

ความเข้าใจผิด

ผมคาดว่า URI.join พฤติกรรมคล้าย Array#join เฉพาะเจาะจง รับ URL fragments มารวมเป็น URL เต็ม

มันไม่ได้ทำแบบนั้น บิ๊กซอร์ไพรส์

ดู code ของ join method มันแค่ iterate over all arguments เรียก merge ทุกตัว

# File uri/rfc2396_parser.rb, line 236
def join(*uris)
  uris[0] = convert_to_uri(uris[0])
  uris.inject :merge
end

merge method ทำสองอย่าง:

  1. แปลง string เช่น "pages" เป็น relative URI object
  2. พยายาม resolve relative URI ไปบน base URI ตาม RFC2396 Section 5.2 อย่างแน่นอน

น่าสนใจ แต่อธิบายพฤติกรรม unexpected ที่กล่าวไว้ได้ไหม?

URI.join("https://www.honeybadger.io", "plans", "change")
# => "https://www.honeybadger.io/change"

ลอง step through โค้ดข้างบน equivalent to:

URI.parse("https://www.honeybadger.io/plans").merge("change")

โค้ดข้างต้นพยายาม resolve relative URI "change" ต่อ absolute URI "https://www.honeybadger.io/plans"

ทำตาม RFC2396 Section 5.2.6 ระบุ:

a) ทุก segment ยกเว้นตัวสุดท้ายของ base URI's path component ถูก copy ไป buffer กล่าวคือ ตัวอักษรหลัง slash ตัวสุดท้าย (right-most) ถูก exclude

b) reference's path component ถูก append ไป buffer string

เล่นตาม:

  1. Copy ทุกอย่างยกเว้น final segment ของ absolute URL ได้ "https://www.honeybadger.io/"
  2. Append relative path ได้ "https://www.honeybadger.io/change"

โลกมีความหมายอีกครั้ง!

สรุป

แม้ URI.join ใช้สร้าง URLs จาก path fragments ได้ แต่ไม่ใช่ designed สำหรับนั้น มัน designed สำหรับ recursive merge URIs ตาม standards ใน RFC

โปรเจกต์ส่วนตัว — สร้าง URLs สำหรับ redirects ไป sales pages ใหม่ — ผมแค่ใช้ Array#join แทน :)

EDIT 8/12/2016: หลังเผยแพร่ ได้ tweets แนะนำใช้ File.join วัตถุประสงค์นี้ มีประโยชน์หลีกเลี่ยง double slashes เช่น /my//path แต่จะเสียบน OSs เช่น Windows ที่ path separator ไม่ใช่ forward-slash