核心誤區:URLEncoder 不是 URL 編碼器
java.net.URLEncoder 類名極具誤導性,其 Javadoc 首句即說明:Utility class for HTML form encoding。它實現的是 application/x-www-form-urlencoded(表單編碼),而非 RFC 3986 定義的 URL 百分號編碼。
陷阱實例
場景 1:查詢參數值包含特殊字符
// 正確:查詢參數值用 URLEncoder
String q = URLEncoder.encode("You & I", "UTF-8"); // "You+%26+I"
String url = "https://foo.com/search?q=" + q; // 可行
空格變 +,& 變 %26,符合表單編碼規則。
場景 2:路徑段落包含特殊字符
// 錯誤:路徑段落用 URLEncoder
String path = URLEncoder.encode("You & I", "UTF-8"); // "You+%26+I"
String url = "https://foo.com/search/" + path; // 解碼後變 "/search/You+&+I" 錯誤!
路徑中 + 不會被解碼為空格,導致語義錯誤。
更深層陷阱:URI / HttpBuilder 的雙重編碼
java.net.URI 多參數建構子假設路徑「已正確編碼 /,其餘未編碼」,導致 /foo%2Fbar 被再次編碼為 /foo%252Fbar。Groovy HttpBuilder 內部依賴 URI,同樣受影響。
正確解決方案:分層編碼策略
URL 各組件編碼規則不同,必須分別處理:
| 組件 | 允許未編碼字符 | 需編碼字符示例 |
| Scheme | 字母數字 + - . | — |
| Host | 域名規則 | — |
| Port | 數字 | — |
| Path Segment | 字母數字 - . _ ~ @ : | / ? # [ ] 空格 & = |
| Query Param Name/Value | 字母數字 - . _ ~ | 空格 & = + # ? / |
| Fragment | 查詢規則類似 | — |
推薦庫:UrlBuilder(或 OkHttp HttpUrl、Spring UriComponentsBuilder)
// UrlBuilder 風格流式 API
String url = UrlBuilder.forHost("http", "foo.com")
.pathSegment("with spaces") // 自動編碼空格 → %20
.pathSegments("path", "with", "varArgs")
.pathSegment("&=?)") // 路徑中 & = ? 需編碼
.queryParam("fancy + name", "fancy?=value") // 參數值編碼
.matrixParam("matrix", "param?") // 矩陣參數
.fragment("#?=")
.toUrlString();
// 結果:https://foo.com/with%20spaces/path/with/varArgs/&%3D%3F%29;matrix=param%3F?fancy%20%2B%20name=fancy%3F%3Dvalue#%23%3F%3D
避坑清單
- 永不直接用
URLEncoder 拼接完整 URL。
- 路徑段落、查詢參數、Fragment 分別編碼。
- 使用成熟構建器(
UriComponentsBuilder、OkHttp HttpUrl),避免手工拼接錯誤。
- 解析 URL 時用
URI 或 HttpUrl.parse,而非正則/字符串分割。
總結
URL 編碼看似簡單,實則暗藏 RFC 3986、RFC 1738、HTML 表單編碼多套規則交織。理解「組件級編碼」原則,配合標準庫構建器,才能構建健壯、安全的網絡請求。
- 上一篇文章: Java int 與 long 轉 byte 陣列及反向轉換工具類實作
- 下一篇文章: C++ 統計字串中英文字母、數字、空格與其他字元個數實作
Copyright ©
程式碼之家 All Rights Reserved