(つ`ω´)つ says to Ubuntu 台灣社群
URL 中的 IPv6 區域識別碼(zone)是個錯誤設計 (★ 103 分) 這篇文章說明網際網路協定第 6 版 (IPv6) 的 link-local 位址(只在同一網路鏈路內有效的位址)在統一資源定位符 (URL, Uniform Resource Locator) 中使用時,會出現相當彆扭的語法問題。IPv6 的每個網路介面都可能有 fe80:: 開頭的 link-local 位址;若同一台機器有多張網路卡,就必須用 zone 或 scope(區域識別碼)指定要走哪個介面,例如 Linux 上可能寫成 `fe80::4%eth0` ,Windows 則常用介面 ID。IPv6 位址本身使用冒號,因此放進 host:port 格式時必須加方括號,例如 ` [fe80::4]:80 ` ;若再加上 zone,就會變成 ` [fe80::4%eth0]:80 ` 。 問題出在 URL 中的百分比符號另有用途:它是百分比編碼(percent-encoding)的起始符號,用來表示 URL 語法中不能直接出現的字元。作者用 Go 語言標準函式庫 `net/url` 解析 `http://[fe80::4%eth0]:80` 時,會得到 invalid URL escape 錯誤,因為 `%et` 被視為不合法的編碼。正確寫法是把 zone 前面的 `%` 本身也編碼成 `%25`,也就是 `http://[fe80::4%25eth0]:80` ;Go 解析後會把主機名稱還原成 `fe80::4%eth0`。作者起初認為這缺乏 URL 指引,後來補充更正:RFC 6874(網際網路標準文件,定義 IPv6 zone 在 URI 中的表示方式)確實規定要使用 `%25`,只是這種使用體驗很糟。 文章也指出,這不是 Go 獨有的問題;nginx、Python requests 等工具與函式庫也曾遇到類似邊界案例。瀏覽器更複雜,因為 link-local IPv6 zone 會衝擊瀏覽器的 origin(來源,同源安全模型的基礎)判定,因此相關草案試圖定義瀏覽器可接受的 zone origin。作者最後表示,為了讓 Anubis 能指向帶 zone 的 IPv6 位址,現階段只能要求使用 `%25` 這種不直覺的寫法;由於不打算分叉 Go 標準函式庫,只能接受這個少見但惱人的限制。 Hacker News 討論中,Go `net/url` 維護者指出 Go 的行為其實符合 RFC 6874:URL 中若要放 `fe80::4%eth0`,就必須寫成 `http://[fe80::4%25eth0]/`。但其他留言也補充,RFC 9844 後來取代 RFC 6874,並移除 URI(統一資源識別符,Uniform Resource Identifier)相關指引,原因是瀏覽器實作方認為原方案不切實際;這讓標準狀態變得尷尬。維持既有 `%25` 語法會醜但相容,改成未編碼 `%` 則不符合既有標準且會破壞既有使用者,雙軌支援又可能帶來更多混亂。 討論也延伸到 IPv6 link-local 位址的實務價值與風險。有些人認為一般網頁服務不該跑在 fe80:: 位址上,私有可路由環境應使用 ULA(Unique Local Address,IPv6 的私有位址範圍);但也有人指出 link-local 位址在無路由器設備佈署、雲端或資料中心交換器之間的 BGP(Border Gateway Protocol,邊界閘道協定)連線、以及明確指定某個網路介面時很有用。另有留言抱怨 IPv6 使用冒號與方括號造成許多工具相容性問題,例如舊版 rsync 在 macOS 上解析 IPv6 目標路徑時會出錯;也有人提醒 Python `ipaddress` 可接受含 shell 特殊字元的 zone ID,若程式把「已驗證」的輸入直接丟進 shell,仍可能造成命令注入。整體看來,社群共識不是 Go 做錯,而是 IPv6 zone、URL 編碼、瀏覽器安全模型與舊工具語法交疊後,形成了一個標準上有依據、實務上很難用的角落案例。 👥 77 則討論、評論 💬 https://news.ycombinator.com/item?id=48405019