常見問題:使用 HttpURLConnection.getContentType() 僅得到 text/html,缺少 charset=gb2312。根因在於 HTTP 回應標頭與 HTML 頁面內部 meta 標籤是兩個獨立層面。
HTTP/1.1 200 OK
Date: Mon, 01 Sep 2008 23:13:31 GMT
Server: Apache/2.2.4
Content-Type: text/html;charset=UTF-8 ← 標頭在此
...其他標頭...
<html> ← 實體內容從這裡開始
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> ← 頁面內宣告
...
connection.getContentType() 或 getHeaderField("Content-Type")。若伺服器正確設定,可直接解析出 charset。<meta http-equiv="Content-Type" content="..."/> 或 HTML5 <meta charset="..."/>。juniversalchardet (Mozilla 移植) 或 ICU4J 根據位元組統計特徵推測編碼。meta 標籤中的空格 content="text/html; charset=gb2312" 導致標頭解析失敗 —— 錯誤,標頭與頁面內容完全分離,空格無關。new String(bytes) 依賴平台預設編碼 —— 極不穩定,跨平台部署必現亂碼。public String fetchWithCharsetDetection(URL url) throws IOException {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
String contentType = conn.getContentType();
String charset = extractCharsetFromContentType(contentType);
InputStream in = conn.getInputStream();
byte[] bytes = readAllBytes(in); // 或邊讀邊檢測
if (charset == null) {
// 1. 嘗試從 HTML meta 解析
String htmlPreview = new String(bytes, 0, Math.min(bytes.length, 4096), "ISO-8859-1");
charset = extractCharsetFromMeta(htmlPreview);
}
if (charset == null) {
// 2. 自動偵測
charset = UniversalDetector.detectCharset(bytes);
}
if (charset == null) charset = "UTF-8"; // 最後回退
return new String(bytes, charset);
}
正確獲取網頁編碼需遵循「標頭 → Meta → 自動偵測」三級回退策略,切勿單一依賴任何單一來源。