Проблема с Android Java UTF-8 HttpClient - PullRequest
16 голосов
/ 19 декабря 2010

У меня странные проблемы с кодировкой символов в массиве JSON, который извлекается с веб-страницы.Сервер отправляет обратно этот заголовок:

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

Также я могу посмотреть на вывод JSON в Firefox или любом браузере, и символы Юникода отображаются правильно.Ответ иногда будет содержать слова из другого языка с символами ударения и тому подобное.Однако я получаю эти странные знаки вопроса, когда я опускаю их и помещаю в строку в 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();
}

Как видите, я указываю UTF-8 в InputStreamReader, но каждый раз, когда я просматриваю возвращенный текст JSON через Toast, он имеет странные знаки вопроса.Я думаю, что вместо этого мне нужно отправить InputStream в байт []?

Заранее благодарен за любую помощь.

Ответы [ 5 ]

38 голосов
/ 19 декабря 2010

Попробуйте это:

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
}
5 голосов
/ 19 декабря 2010

@ Ответ Архимеда - решение. Но я не вижу ничего явно неправильного в вашем convertStreamToString коде.

Мои предположения:

  1. Сервер устанавливает метку порядка байтов UTF (BOM) в начале потока. Стандартный символьный декодер Java UTF-8 не удаляет спецификацию, поэтому есть вероятность, что она окажется в результирующей строке. (Тем не менее, код для EntityUtils, похоже, тоже ничего не делает с BOM.)
  2. Ваш convertStreamToString читает поток символов по очереди и заново собирает его, используя аппаратный '\n' в качестве маркера конца строки. Если вы собираетесь записать это во внешний файл или приложение, вам, вероятно, следует использовать маркер конца строки для конкретной платформы.
1 голос
/ 28 июля 2014

Просто ваш convertStreamToString не поддерживает кодировку, установленную в HttpRespnose. Если вы загляните внутрь EntityUtils.toString(entity, HTTP.UTF_8), то увидите, что EntityUtils выясняет, есть ли сначала кодировка, установленная в HttpResponse, а затем, если она есть, 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 голосов
/ 03 декабря 2015

Извлечь кодировку из поля типа содержимого ответа. Для этого вы можете использовать следующий метод:

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:

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

InputStreamReader inReader = (TextUtils.isEmpty(charsetName) ? new InputStreamReader(inputStream) :
                    new InputStreamReader(inputStream, charsetName));
            BufferedReader reader = new BufferedReader(inReader);
0 голосов
/ 01 декабря 2015

Архимед ответ правильный.Однако это можно сделать, просто указав в 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...