2010-12-18 9 views
15

Bir web sayfasından yakalanan bir JSON dizisiyle garip karakter kodlaması sorunları yaşıyorum. Sunucu bu kafayla geri gönderiyor:Android Java UTF-8 HttpClient Sorun

Content-Type text/javascript; charset = UTF-8

Ayrıca ben Firefox'ta JSON çıktı veya herhangi bir tarayıcıda bakabilirsiniz ve Unicode karakterleri düzgün görüntülemek. Yanıt bazen aksan sembolleri ve benzeri başka bir dilde kelimeleri içerecektir. Ancak, indirdiğimde ve Java'da bir dizeye koyduğumda bu garip soru işaretlerini alıyorum. Gördüğünüz gibi, ben InputStreamReader üzerinde UTF-8 belirterek ediyorum ama Toast üzerinden geri JSON metnini görüntülemek her zaman garip soru işaretleri var

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(); 
} 

: İşte benim kodudur. Ben InputStream yerine bir byte [] göndermek gerektiğini düşünüyorum?

Yardımlarınız için şimdiden teşekkür ederiz. Arhimed cevabı @

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 
} 

cevap

37

bu deneyin. Ama convertStreamToString kodunuzda açıkça yanlış bir şey göremiyorum.

Benim tahmin niteliğindeki:

  1. sunucu akışının başlangıcında bir UTF Byte Order Mark (BOM) koyuyor. Standart Java UTF-8 karakter kod çözücüsü, BOM'u kaldırmaz, bu yüzden sonuçta ortaya çıkan String'de sonuçlanır. (Ancak, EntityUtils kodu, BOM'lar ile herhangi bir şey yapmıyor gibi görünmüyor.)
  2. convertStreamToString, karakter akışını bir kerede bir satır okuyor ve bir sabit kablolu '\n' kullanarak yeniden kuruyor. çizgi işaretçisi. Bunu bir harici dosyaya veya uygulamaya yazacaksanız, muhtemelen platforma özel bir satır sonu işareti kullanmalısınız.
+0

Teşekkür:

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; } 

Sonra InputStreamReader oluşturmak için çıkarılan charset kullanın. Değişikliklerinizi ekledim ve EntityUtils için ekstra Apache öğelerini aldım ancak şimdi uygulama beklenmedik şekilde EntityUtils.toString satırında sonlandırılıyor. program derler ve çalışır, ancak toString'i çağırmadan önce varlığa bir şeyler yapmam gerekir mi? –

+0

boşver. Ben bir aptalım ve benim URL'mle bir şeyleri karıştırdım. İşe yarıyor! Karakterler doğru şekilde işlenir! –

+3

@Michael: Bu cevap çok iyi ve eğer soruyu sorsaydım bunu kabul ederdim. – SK9

5

çözümdür:

1

Bu, convertStreamToString öğesinin HttpRespnose'da ayarlanan kodlamayı onurlandırması değil. EntityUtils.toString(entity, HTTP.UTF_8)'un içine bakarsanız, EntityUtils'in ilk önce HttpResponse'de kodlama kümesinin olup olmadığını öğreneceğini görürsünüz. Varsa, EntityUtils bu kodlamayı kullanır. Varlıkta kodlama yoksa, yalnızca parametrede geçirilen kodlamaya (bu durumda HTTP.UTF_8) geri döner.

Yani HTTP.UTF_8 parametresinde geçirilir ama yanlış kodlama olduğu için alışamıyorsun söyleyebiliriz. Bu yüzden EntityUtils'in yardımcısı yöntemiyle kodunuz güncellenmektedir.

  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

Arşimed'in cevabı doğrudur. Ancak, bu HTTP isteğinde ek bir başlık sağlayarak basitçe yapılabilir:

Accept-charset: utf-8 

şey kaldırmak veya başka bir kütüphaneyi kullanmaya gerek yoktur. Örneğin

,

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 

Büyük ihtimalle isteğiniz herhangi Accept-Charset başlık yok.

0

Karakter kümesini, yanıt içeriği türü alanından çıkarın. Bunu yapmak için aşağıdaki yöntemi kullanabilirsiniz: cevap için

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

InputStreamReader inReader = (TextUtils.isEmpty(charsetName) ? new InputStreamReader(inputStream) : 
        new InputStreamReader(inputStream, charsetName)); 
      BufferedReader reader = new BufferedReader(inReader);