Метод сброса OutputStreamWriter выдает IOException при попытке написать китайские символы

1

Ниже приведен код, который я использую для отправки SOAP-запросов в моем приложении для Android, и он отлично работает со всеми запросами, кроме одного. Этот код генерирует IOException: длина содержимого превышает на wr.flush();, когда есть китайские символы в переменной requestBody.

Длина содержимого в этом случае равна 409

            URL url = new URL(Constants.HOST_NAME);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            // Modify connection settings
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
            connection.setRequestProperty("SOAPAction", soapAction);

            String requestBody = new String(soapRequest.getBytes(),"UTF-8");
            int lngth = requestBody.length();
            connection.setRequestProperty("Content-Length", (""+lngth));

            // Enable reading and writing through this connection
            connection.setDoInput(true);
            connection.setDoOutput(true);

            // Connect to server
            connection.connect();

            OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
            wr.write(requestBody);
            wr.flush();
            wr.close();

Любые подсказки, что происходит не так, когда в строке есть китайские символы?

EDIT: я удалил поле заголовка content-lenght и он работает, но почему?

Теги:
soap
httpurlconnection
ioexception
cjk

3 ответа

1
Лучший ответ

Чтобы упростить другой ответ: Content-Length ДОЛЖЕН быть длиной в байтах, и вы указываете длину в символах (тип 16-бит char). В общем, они разные. Поскольку UTF-8 является кодировкой с переменной длиной байта, существует разница для чего-либо, кроме основного 7-битного диапазона ASCII. Другой ответ показывает правильный способ написания кода.

  • 0
    спасибо, это уточнение помогло. Я из C / C ++ фона и никогда не понимал, что Java имеет 16-битный тип символов :)
3

Этот код задает свойство Content-Length запроса количеству символов в строковом представлении сообщения:

String requestBody = new String(soapRequest.getBytes(),"UTF-8");
int lngth = requestBody.length();
connection.setRequestProperty("Content-Length", (""+lngth));

Но затем вы преобразовываете это строковое представление обратно в байты перед записью:

OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");

Итак, вы в конечном итоге пишете больше байт, чем вы утверждали. Вы столкнетесь с той же проблемой с любыми символами, отличными от ASCII. Вместо этого вы должны сделать что-то вроде этого (copy-and-paste, поэтому могут иметь синтаксические ошибки):

byte[] message = soapRequest.getBytes();
int lngth = message.length;
connection.setRequestProperty("Content-Length", (""+lngth));

// ...

connection.getOutputStream().write(message);
0

Я предполагаю, что вы не превратили китайский в utf-8. Если вы поддерживаете пользователей, вводящих двойные и расширенные наборы символов в свои поля, вам необходимо убедиться, что вы конвертируете свои входы с этих наборов символов (ASCII, UNICODE или UCS) в UTF-8.

Как только вы определяете кодировки символов, с которыми работаете, вы можете использовать что-то вроде:

FileInputStream(inputFile), "inputencoding");
Writer output = new OutputStreamWriter(new FileOutputStream(outputFile), "outputencoding");

Ссылка

при создании ваших потоков для чтения/записи для преобразования между двумя.

Другой альтернативой является поиск свойства запроса, управляющего языком HTTP-запроса. Я мало что знаю об этом.

  • 0
    Я работаю с UTF-8 и переменная requestBody уже закодирована. И упоминание кодировки при создании выходного потока тоже не помогает (отредактировано в оригинальном посте).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню