2014-06-05 9 views
9

pory używałem następujący fragment kodu w celu wysyłania i odbierania ciągów JSON:Wysyłanie UTF-8 przy użyciu ciąg HttpURLConnection

static private String sendJson(String json,String url){ 
    HttpClient httpClient = new DefaultHttpClient(); 
    String responseString = ""; 
    try { 
     HttpPost request = new HttpPost(url); 
     StringEntity params =new StringEntity(json, "UTF-8"); 
     request.addHeader("content-type", "application/json"); 
     request.setEntity(params); 
     HttpResponse response = httpClient.execute(request); 
     HttpEntity entity = response.getEntity(); 
     responseString = EntityUtils.toString(entity, "UTF-8"); 

    }catch (Exception ex) { 
     ex.printStackTrace(); 
     // handle exception here 
    } finally { 
     httpClient.getConnectionManager().shutdown(); 
    } 
    return responseString; 
} 

Powyższy kod działa wyśmienicie nawet jeśli ciąg json zawierały UTF-8 znaki i wszystko działało dobrze.

Z kilku powodów musiałem zmienić sposób wysyłania żądań HTTP i używać HttpURLConnection zamiast HttpClient Apache'a. Oto mój kod:

static private String sendJson(String json,String url){ 
    String responseString = ""; 
    try { 
     URL m_url = new URL(url); 
     HttpURLConnection conn = (HttpURLConnection)m_url.openConnection(); 
     conn.setDoInput(true); 
     conn.setDoOutput(true); 
     conn.setUseCaches(false); 
     conn.setRequestMethod("POST"); 
     conn.setRequestProperty("content-type", "application/json"); 
     DataOutputStream outputStream = new DataOutputStream(conn.getOutputStream()); 
     outputStream.writeBytes(json); 
     outputStream.flush(); 
     outputStream.close(); 

     BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); 
     StringBuilder sb = new StringBuilder(); 
     String line; 
     while ((line = br.readLine()) != null) { 
      sb.append(line+"\n"); 
     } 
     br.close(); 
     responseString = sb.toString(); 
    } catch (MalformedURLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    return responseString; 
} 

Ten kod działa dobrze dla zwykłych znaków angielskich, ale nie wydaje się, aby obsługiwać UTF-8 znaków w ciąg json, gdyż nie za każdym razem. (podczas wysyłania json do serwera, serwer miażdży mówiąc, że utf8 nie może dekodować określonego bajtu, ale kiedy otrzymuję utf8 json z serwera, wydaje mi się, że działa, ponieważ udało mi się zobaczyć znaki specjalne).

Serwer w ogóle się nie zmienił i działał poprawnie z poprzednim kodem, więc problem dotyczy w 100% nowego fragmentu kodu.

Każdy pomysł, jak naprawić ciąg znaków json, aby mógł obsługiwać kodowanie UTF 8? Dzięki

Odpowiedz

22

Myślę, że problem jest w tej części:

DataOutputStream outputStream = new DataOutputStream(conn.getOutputStream()); 
outputStream.writeBytes(json); 
outputStream.flush(); 
outputStream.close(); 

Zamiast robić to trzeba kodować JSON jako UTF-8
i wysłać te bajty reprezentujące kodowanie UTF-8.

Spróbuj użyć tego:

Charset.forName("UTF-8").encode(json) 

Patrz:

Charset.encode

Jeszcze prostszym sposobem jest użycie np a BufferedWriter owijając jeden z następujących elementów: . OutputStreamWriter wie o własnym kodowaniu, więc zrobi to za Ciebie (kodowanie ciągu znaków json).

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), "UTF-8")); 
bw.write(json); 
bw.flush(); 
bw.close(); 
+2

Perfect. Dziękuję i życzę miłego dnia. – Jjang

1

Pisząc String do strumienia wyjściowego (bajtów), trzeba określić kodowanie zrobić konwersję. Jednym ze sposobów jest owinięcie strumienia wyjściowego w OutputStreamWriter, który będzie używał zestawu znaków UTF-8 do kodowania.

 conn.setRequestProperty("content-type", "application/json; charset=utf-8"); 
     Writer writer = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), "UTF-8")); 
     writer.write(json); 
     writer.close(); 

flush() jest również opcjonalny jeśli zadzwonisz close().

Inną opcją, o której wspomniał już peter.petrov, jest najpierw przekonwertować twój String na bajty (w pamięci), a następnie wypisać tablicę bajtów do strumienia wyjściowego.

Aby było to oczywiste po stronie serwera, można przekazać zestaw znaków użyty w nagłówku typu treści ("content-type", "application/json; charset=utf-8").

1

StringEntity używa Charset, aby upewnić się, że kodowanie jest prawidłowe.Czyni ~ że:

byte[] content = s.getBytes(charset); 

Bez większych zmian w kodzie, Twój zapisu może być:

outputStream.write(json.getBytes("UTF-8")); 

Jak do odczytu, nie ma sensu w użyciu BufferedReader z readLine wyjątkiem normalizowanie koniec linii. Jest znacznie wolniejszy od innych metod, ponieważ wymaga odczytywania każdego bajtu osobno.

EntityUtils robi głównie że:

Reader reader = new InputStreamReader(conn.getInputStream(), "UTF-8"); 
    StringBuilder buffer = new StringBuilder(); 
    char[] tmp = new char[1024]; 
    int l; 
    while((l = reader.read(tmp)) != -1) { 
     buffer.append(tmp, 0, l); 
    } 
    responseString = buffer.toString();