2010-12-18 6 views
15

Webページから取得されたJSON配列で奇妙な文字エンコードの問題が発生しています。サーバーはこのヘッダーを返送しています。Android Java UTF-8 HttpClientの問題

コンテンツタイプテキスト/ javascript; charset = UTF-8

また、FirefoxやブラウザのJSON出力やUnicode文字が正しく表示されます。応答には、アクセント記号などを含む別の言語の単語が含まれることがあります。しかし、私はそれをプルダウンしてJavaの文字列に置くと、それらの奇妙な疑問符を得ています。ここに私のコードは次のとおりです。

HttpParams params = new BasicHttpParams(); 
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
HttpProtocolParams.setContentCharset(params, "utf-8"); 
params.setBooleanParameter("http.protocol.expect-continue", false); 

HttpClient httpclient = new DefaultHttpClient(params); 

HttpGet httpget = new HttpGet("http://www.example.com/json_array.php"); 
HttpResponse response; 
    try { 
     response = httpclient.execute(httpget); 

     if(response.getStatusLine().getStatusCode() == 200){ 
      // Connection was established. Get the content. 

      HttpEntity entity = response.getEntity(); 
      // If the response does not enclose an entity, there is no need 
      // to worry about connection release 

      if (entity != null) { 
       // A Simple JSON Response Read 
       InputStream instream = entity.getContent(); 
       String jsonText = convertStreamToString(instream); 

       Toast.makeText(getApplicationContext(), "Response: "+jsonText, Toast.LENGTH_LONG).show(); 

      } 

     } 


    } catch (MalformedURLException e) { 
     Toast.makeText(getApplicationContext(), "ERROR: Malformed URL - "+e.getMessage(), Toast.LENGTH_LONG).show(); 
     e.printStackTrace(); 
    } catch (IOException e) { 
     Toast.makeText(getApplicationContext(), "ERROR: IO Exception - "+e.getMessage(), Toast.LENGTH_LONG).show(); 
     e.printStackTrace(); 
    } catch (JSONException e) { 
     Toast.makeText(getApplicationContext(), "ERROR: JSON - "+e.getMessage(), Toast.LENGTH_LONG).show(); 
     e.printStackTrace(); 
    } 

private static String convertStreamToString(InputStream is) { 
    /* 
    * To convert the InputStream to String we use the BufferedReader.readLine() 
    * method. We iterate until the BufferedReader return null which means 
    * there's no more data to read. Each line will appended to a StringBuilder 
    * and returned as String. 
    */ 
    BufferedReader reader; 
    try { 
     reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); 
    } catch (UnsupportedEncodingException e1) { 
     // TODO Auto-generated catch block 
     e1.printStackTrace(); 
    } 
    StringBuilder sb = new StringBuilder(); 

    String line; 
    try { 
     while ((line = reader.readLine()) != null) { 
      sb.append(line + "\n"); 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     try { 
      is.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    return sb.toString(); 
} 

あなたが見ることができるように、私はInputStreamReaderの上でUTF-8を指定していますが、私はトーストを介して返さJSONテキストを表示するたびに、それは奇妙な疑問符を持っています。代わりにbyte []に​​InputStreamを送る必要があると思っていますか?

ご協力いただきありがとうございます。 Arhimedの答え@

if (entity != null) { 
    // A Simple JSON Response Read 
    // InputStream instream = entity.getContent(); 
    // String jsonText = convertStreamToString(instream); 

    String jsonText = EntityUtils.toString(entity, HTTP.UTF_8); 

    // ... toast code here 
} 

答えて

37

が、これは試してみてください。しかし、私はあなたのconvertStreamToStringコードで明らかに間違ったことは何も見ることができません。

私の推測は、次のとおりです。

  1. サーバは、ストリームの開始時にUTFのバイトオーダーマーク(BOM)を入れています。標準のJava UTF-8文字デコーダーはBOMを削除しないので、結果として得られるStringに終わる可能性があります。 (ただし、EntityUtilsのコードではBOMも何もしないようです。)
  2. convertStreamToStringは、一度に1行ずつ文字ストリームを読み込み、ハードワイヤードの'\n'を使用して再アセンブリしています。ラインマーカー。そのファイルを外部のファイルやアプリケーションに書き込む場合は、おそらくプラットフォーム固有の行末マーカーを使用する必要があります。
+0

ありがとう:

private static String extractCharsetFromContentType(String contentType) { if (TextUtils.isEmpty(contentType)) return null; Pattern p = Pattern.compile(".*charset=([^\\s^;^,]+)"); Matcher m = p.matcher(contentType); if (m.find()) { try { return m.group(1); } catch (Exception e) { return null; } } return null; } 

はその後InputStreamReaderを作成するために、抽出された文字セットを使用します。私はあなたの変更を追加し、EntityUtils用の余分なApacheのものをインポートしましたが、今度はEntityUtils.toString行で予期せず終了します。プログラムをコンパイルして実行しますが、toStringを呼び出す前に何かを実行する必要がありますか? –

+0

心配しないでください。私はばかだったし、私のURLで何かを台無しにした。できます!文字は正しくレンダリングされます。 –

+3

@Michael:この回答はとても良いです。私が質問したら、これを受け入れます。 – SK9

5

ソリューションです:

1

あなたのconvertStreamToStringがHttpRespnoseでエンコードされたエンコードを受け入れていないということだけです。 EntityUtils.toString(entity, HTTP.UTF_8)の内部を見ると、まずHttpResponseにエンコーディングセットがあるかどうかをEntityUtilsが確認し、存在する場合はEntityUtilsがそのエンコーディングを使用することがわかります。エンティティにエンコーディングが設定されていない場合は、パラメータで渡されたエンコーディング(この場合はHTTP.UTF_8)にのみ戻ります。

HTTP.UTF_8がパラメータで渡されたとは言えますが、間違ったエンコーディングであるため使用されることはありません。そこで、EntityUtilsのヘルパーメソッドを使用してコードを更新します。

  HttpEntity entity = response.getEntity(); 
      String charset = getContentCharSet(entity); 
      InputStream instream = entity.getContent(); 
      String jsonText = convertStreamToString(instream,charset); 

    private static String getContentCharSet(final HttpEntity entity) throws ParseException { 
    if (entity == null) { 
     throw new IllegalArgumentException("HTTP entity may not be null"); 
    } 
    String charset = null; 
    if (entity.getContentType() != null) { 
     HeaderElement values[] = entity.getContentType().getElements(); 
     if (values.length > 0) { 
      NameValuePair param = values[0].getParameterByName("charset"); 
      if (param != null) { 
       charset = param.getValue(); 
      } 
     } 
    } 
    return TextUtils.isEmpty(charset) ? HTTP.UTF_8 : charset; 
} 



private static String convertStreamToString(InputStream is, String encoding) { 
    /* 
    * To convert the InputStream to String we use the 
    * BufferedReader.readLine() method. We iterate until the BufferedReader 
    * return null which means there's no more data to read. Each line will 
    * appended to a StringBuilder and returned as String. 
    */ 
    BufferedReader reader; 
    try { 
     reader = new BufferedReader(new InputStreamReader(is, encoding)); 
    } catch (UnsupportedEncodingException e1) { 
     // TODO Auto-generated catch block 
     e1.printStackTrace(); 
    } 
    StringBuilder sb = new StringBuilder(); 

    String line; 
    try { 
     while ((line = reader.readLine()) != null) { 
      sb.append(line + "\n"); 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     try { 
      is.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    return sb.toString(); 
} 
0

アルキメドの答えは正しいです。しかし、それは、HTTPリクエストに追加のヘッダーを提供することにより、簡単に行うことができます。

Accept-charset: utf-8 

何かを削除したり、他のライブラリを使用する必要はありませんが。

例えば、

GET/HTTP/1.1 
Host: www.website.com 
Connection: close 
Accept: text/html 
Upgrade-Insecure-Requests: 1 
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.10 Safari/537.36 
DNT: 1 
Accept-Encoding: gzip, deflate, sdch 
Accept-Language: en-US,en;q=0.8 
Accept-Charset: utf-8 

は、おそらくあなたの要求は、任意のAccept-Charsetヘッダーを持っていません。

0

応答コンテンツタイプフィールドから文字セットを抽出します。これを行うには、次の方法を使用することができます応答のための

String charsetName = extractCharsetFromContentType(connection.getContentType()); 

InputStreamReader inReader = (TextUtils.isEmpty(charsetName) ? new InputStreamReader(inputStream) : 
        new InputStreamReader(inputStream, charsetName)); 
      BufferedReader reader = new BufferedReader(inReader); 
関連する問題