2013-06-27 41 views
2

我解決了檢索和顯示非UTF-8字符時遇到的問題,但我不明白爲什麼我的解決方案有效。包含非UTF-8字符的源HTTP GET

以下代碼:

final HttpClient client = new HttpClient(); 
final HttpMethod method = new GetMethod(urlString); 
client.executeMethod(method); 
final String responseBodyAsString = method.getResponseBodyAsString(); 
System.out.println(responseBodyAsString); 

被搞亂了所述顯示器上的一些字符,例如YáñEZ

我改變:

final String responseBodyAsString = method.getResponseBodyAsString(); 

final ByteBuffer inputBuffer = ByteBuffer.wrap(method.getResponseBody()); 
final String responseBodyAsString = new String(inputBuffer.array()); 

和與之前相同的字符串正確表示爲亞涅斯

爲什麼?

+2

要求服務器發送UTF-8數據的正確方法是使用「Accept-Charset:utf-8」請求標頭,而不是「Content-Type」請求標頭。 –

+0

最重要的是,正確的方法是不改變字符。許多人的事情「哦,這只是一個帶有扭曲的n」,但事實上這是一封不同的信。如果某些軟件將Q改爲O,那麼你會怎麼看?「好吧,它只是帶着一個扭曲的O」 –

+0

@RemyLebeau看到我的更新,它解決了問題。我不必指定字符集或內容類型。那是因爲httpclient有一些知道要使用什麼字符的機制? – Lolo

回答

1

getResponseBodyAsString()使用HTTP響應的Content-Type頭知道響應身體的字符集是什麼,從而所需要的數據可以被轉換爲一個StringgetResponseBody()只是原樣返回主體的原始字節,然後使用平臺的默認字符集轉換爲String。由於您可以通過手動轉換原始字節來獲得所需的String輸出,這表明HTTP服務器根本沒有在響應的Content-Type頭中指定字符集,或者指定了錯誤的字符集。

YáñezYáñez的UTF-8編碼的版本,因此它是奇怪的是,String(bytes[])構造函數可以把它正確解碼,除非該平臺的默認字符集實際上是UTF-8。如果使用的響應字符集是ISO-8859-1,則getResponseBodyAsString()返回Yáñez,這是text/...媒體類型的默認字符集,當按照RFC 2616第3.7.1節沒有明確指定charset時通過HTTP發送。

在懷疑getResponseBodyAsString()的錯誤之前,我會建議在發送數據的服務器腳本中查找錯誤(或向服務器管理員報告錯誤報告)。您可以使用Wireshark之​​類的數據包嗅探器或調頻代理(如Fiddler)來確認響應Content-Type標題中缺失/無效的字符集。

+0

很好的解釋,謝謝。我做了wget -d,看到你在懷疑什麼:在響應中沒有指定字符集:「Accept-Ranges:bytes ... Content-Type:text/xml」。我不明白你對String(bytes [])正確解碼的奇怪之處,除非平臺是UTF-8。這不是相反的嗎?即只有當平臺支持一套能夠展示亞涅斯的作品時,它才能起作用嗎?我在Mac的FYI上用Eclipse運行我的代碼。 – Lolo

1

嘗試下一:

private static final String UNICODE = "ÀàÈèÌìÒòÙùÁáÉéÍíÓóÚúÝýÂâÊêÎîÔôÛûŶŷÃãÕõÑñÄäËëÏïÖöÜüŸÿÅåÇçŐőŰű"; 
private static final String PLAIN_ASCII = "AaEeIiOoUuAaEeIiOoUuYyAaEeIiOoUuYyAaOoNnAaEeIiOoUuYyAaCcOoUu"; 

public static String convertNonAscii(String str) { 
    if (str == null) { 
     return null; 
    } 
    StringBuilder sb = new StringBuilder(); 
    for (int i = 0; i < str.length(); i++) { 
     char c = str.charAt(i); 
     int pos = UNICODE.indexOf(c); 
     if (pos > -1) 
      sb.append(PLAIN_ASCII.charAt(pos)); 
     else { 
      sb.append(c); 
     } 
    } 
    return sb.toString(); 
} 

public static void main(String[] args) { 
    Pattern p = Pattern.compile("[^\\x00-\\x7E]", Pattern.CASE_INSENSITIVE); 
    System.out.println(p.matcher(UNICODE).find()); 
    System.out.println(p.matcher(PLAIN_ASCII).find()); 
    System.out.println(convertNonAscii("ú or ñ")); 
} 

輸出:

true 
false 
u or n 
+0

感謝您提供轉換代碼。 – Lolo

相關問題