後台收到 URL 編碼字符串 %D7%AE%EF%BF%BD%EF%BF%BD%2F015.JPG,使用 URLDecoder.decode(str, "UTF-8") 解碼出現亂碼。
%D7%AE 是 **GBK/GB2312** 編碼的中文「圖」字雙字節。%EF%BF%BD 是 UTF-8 中「替換字符」 () 的編碼,說明字節流在某個環節被錯誤轉碼。
| 函數 | 編碼方式 | 不編碼字符 | 適用場景 |
|---|---|---|---|
escape() | ISO Latin-1 (單字節) | @ * / + | 舊項目、非 UTF-8 頁面 |
encodeURI() | UTF-8 | ! @ # $ & * ( ) = : / ; ? + ' ~ | 整個 URL,保留結構字符 |
encodeURIComponent() | UTF-8 | ! ' ( ) * ~ | 推薦:單個參數值,編碼最全 |
// 前端 JS
var param = "中文文件名.jpg";
var url = "upload.action?file=" + encodeURIComponent(param); // UTF-8 編碼
// 發送請求...
// 後端 Java (Spring MVC 自動處理,或手動)
String file = request.getParameter("file");
// Spring MVC 已自動按 UTF-8 解碼,直接用 file 即可
// 若手動:
// String decoded = java.net.URLDecoder.decode(file, StandardCharsets.UTF_8.name());
關鍵配置:
// 前端:頁面 charset=GB2312
var url = "upload.action?file=" + escape(param); // escape 產生 %D7%AE...
// 後端:指定 GBK 解碼
String decoded = java.net.URLDecoder.decode(file, "GBK");
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
public class UrlDecodeUtil {
public static String decodeUtf8(String encoded) {
try {
return URLDecoder.decode(encoded, StandardCharsets.UTF_8.name());
} catch (Exception e) {
// 嘗試 GBK 兼容舊數據
try { return URLDecoder.decode(encoded, "GBK"); }
catch (Exception ex) { return encoded; } // 解碼失敗返回原串
}
}
}
encodeURIComponent (UTF-8) 而非 escape。request.getParameter("file"),觀察 %XX 模式判斷編碼。%EF%BF%BD (替換字符),說明字節流已損壞,**無法完美恢復**,需從源頭修正編碼。