首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

從 HTTP 協議看無法獲取網頁 charset 的原因與解決方案

     編輯:Java 相關知識

常見問題:使用 HttpURLConnection.getContentType() 僅得到 text/html,缺少 charset=gb2312。根因在於 HTTP 回應標頭與 HTML 頁面內部 meta 標籤是兩個獨立層面。

HTTP 回應結構

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" />  ← 頁面內宣告
...

三層檢測策略

  1. 檢查回應標頭 Content-Type:connection.getContentType() 或 getHeaderField("Content-Type")。若伺服器正確設定,可直接解析出 charset。
  2. 解析 HTML meta 標籤:若標頭無 charset,需下載 HTML 內容,正則或解析器提取 <meta http-equiv="Content-Type" content="..."/> 或 HTML5 <meta charset="..."/>。
  3. 自動編碼偵測:以上皆失敗時,使用 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 → 自動偵測」三級回退策略,切勿單一依賴任何單一來源。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved