Странное JAVA UTF-8 кодирование поведения, новая строка (байты, "UTF-8") дает разные результаты в большинстве случаев с похожей настройкой - PullRequest
0 голосов
/ 28 января 2020

Мое приложение должно поддерживать японские символы, поэтому мы использовали UTF-8 в качестве кодировки по умолчанию для всего стека. Мы столкнулись со странной проблемой, когда новая строка (байты, «UTF-8») дает другие результаты.

Ввод от пользователя: 東京
Строка в кодировке Base64, сгенерированная из браузера и отправленная в API: 5p2x5Lqs
Обе системы генерируют один и тот же байтовый массив.
Но только в системе 1 декодированная строка выглядит как 東京
В Системе 2 декодированная строка выглядит как ??

Система 1:
Контейнер: Tomee 7.1.0
JDK: 1.8.0_201-b09
Версия ОС: 3.10.0-957.12.2.el7.x86_64
Архитектура: amd64
Язык:

[logs]$ locale
LANG=en_GB.UTF-8
LC_CTYPE="en_GB.UTF-8"
LC_NUMERIC="en_GB.UTF-8"
LC_TIME="en_GB.UTF-8"
LC_COLLATE="en_GB.UTF-8"
LC_MONETARY="en_GB.UTF-8"
LC_MESSAGES="en_GB.UTF-8"
LC_PAPER="en_GB.UTF-8"
LC_NAME="en_GB.UTF-8"
LC_ADDRESS="en_GB.UTF-8"
LC_TELEPHONE="en_GB.UTF-8"
LC_MEASUREMENT="en_GB.UTF-8"
LC_IDENTIFICATION="en_GB.UTF-8"
LC_ALL=
[logs]$ locale status
locale: unknown name "status"

Система 2:
Контейнер: Tomee 7.1.0
JDK: 1.8.0_201-b09
Версия ОС: 2.6.32-696.18.7 .el6.x86_64
Архитектура: amd64
Язык:

[ logs]$ locale
LANG=en_GB
LC_CTYPE="en_GB"
LC_NUMERIC="en_GB"
LC_TIME="en_GB"
LC_COLLATE="en_GB"
LC_MONETARY="en_GB"
LC_MESSAGES="en_GB"
LC_PAPER="en_GB"
LC_NAME="en_GB"
LC_ADDRESS="en_GB"
LC_TELEPHONE="en_GB"
LC_MEASUREMENT="en_GB"
LC_IDENTIFICATION="en_GB"
LC_ALL=
[ logs]$ locale status
locale: unknown name "status"

Java используемый код

LogUtil.logMessage("searchString before decoding="+searchString);
                 //s =  new String (Base64.decodeBase64(searchString),utf8_test);
                 byte[] decodedBytes=Base64.getDecoder().decode(searchString);
                 byte[] decodedBaytesFromapache=org.apache.commons.codec.binary.Base64.decodeBase64(searchString);
                 System.out.println("java native array :: ");
                 for(byte b:decodedBytes)
                 {
                     System.out.print(b);
                 }
                 System.out.println("\njava apache array :: \n");
                 for(byte b:decodedBaytesFromapache)
                 {
                     System.out.print(b);
                 }
                 s=new String(decodedBytes,"UTF-8"); //Charset.forName("UTF-8") was also tried here
                 System.out.println("\n String post decode:: "+s);
                 System.out.println("");
            //String s = 
                 System.out.println("loaded charset is utf-8:: "+Charset.isSupported("UTF-8"));
                 Set<String> listOfCharsets=Charset.availableCharsets().keySet();
                 System.out.println("Listing supported charsets:: ");
                 for(String item: listOfCharsets)
                 {System.out.println(item); }

Вывод на System1

searchString before decoding=5p2x5Lqs
java native array ::
-26-99-79-28-70-84
java apache array ::

-26-99-79-28-70-84
 String post decode:: 東京

loaded charset is utf-8:: true
Listing supported charsets::
Big5
Big5-HKSCS
CESU-8
EUC-JP
EUC-KR
GB18030
GB2312
GBK
IBM-Thai
IBM00858
IBM01140
IBM01141
IBM01142
IBM01143
IBM01144
IBM01145
IBM01146
IBM01147
IBM01148
IBM01149
IBM037
IBM1026
IBM1047
IBM273
IBM277
IBM278
IBM280
IBM284
IBM285
IBM290
IBM297
IBM420
IBM424
IBM437
IBM500
IBM775
IBM850
IBM852
IBM855
IBM857
IBM860
IBM861
IBM862
IBM863
IBM864
IBM865
IBM866
IBM868
IBM869
IBM870
IBM871
IBM918
ISO-2022-CN
ISO-2022-JP
ISO-2022-JP-2
ISO-2022-KR
ISO-8859-1
ISO-8859-13
ISO-8859-15
ISO-8859-2
ISO-8859-3
ISO-8859-4
ISO-8859-5
ISO-8859-6
ISO-8859-7
ISO-8859-8
ISO-8859-9
JIS_X0201
JIS_X0212-1990
KOI8-R
KOI8-U
Shift_JIS
TIS-620
US-ASCII
UTF-16
UTF-16BE
UTF-16LE
UTF-32
UTF-32BE
UTF-32LE
UTF-8
windows-1250
windows-1251
windows-1252
windows-1253
windows-1254
windows-1255
windows-1256
windows-1257
windows-1258
windows-31j
x-Big5-HKSCS-2001
x-Big5-Solaris
x-COMPOUND_TEXT
x-euc-jp-linux
x-EUC-TW
x-eucJP-Open
x-IBM1006
x-IBM1025
x-IBM1046
x-IBM1097
x-IBM1098
x-IBM1112
x-IBM1122
x-IBM1123
x-IBM1124
x-IBM1166
x-IBM1364
x-IBM1381
x-IBM1383
x-IBM300
x-IBM33722
x-IBM737
x-IBM833
x-IBM834
x-IBM856
x-IBM874
x-IBM875
x-IBM921
x-IBM922
x-IBM930
x-IBM933
x-IBM935
x-IBM937
x-IBM939
x-IBM942
x-IBM942C
x-IBM943
x-IBM943C
x-IBM948
x-IBM949
x-IBM949C
x-IBM950
x-IBM964
x-IBM970
x-ISCII91
x-ISO-2022-CN-CNS
x-ISO-2022-CN-GB
x-iso-8859-11
x-JIS0208
x-JISAutoDetect
x-Johab
x-MacArabic
x-MacCentralEurope
x-MacCroatian
x-MacCyrillic
x-MacDingbat
x-MacGreek
x-MacHebrew
x-MacIceland
x-MacRoman
x-MacRomania
x-MacSymbol
x-MacThai
x-MacTurkish
x-MacUkraine
x-MS932_0213
x-MS950-HKSCS
x-MS950-HKSCS-XP
x-mswin-936
x-PCK
x-SJIS_0213
x-UTF-16LE-BOM
X-UTF-32BE-BOM
X-UTF-32LE-BOM
x-windows-50220
x-windows-50221
x-windows-874
x-windows-949
x-windows-950
x-windows-iso2022jp
searchString after decoding=東京

Выход на Система 2

searchString before decoding=5p2x5Lqs
java native array ::
-26-99-79-28-70-84
java apache array ::

-26-99-79-28-70-84
 String post decode:: ??

loaded charset is utf-8:: true
Listing supported charsets::
Big5
Big5-HKSCS
CESU-8
EUC-JP
EUC-KR
GB18030
GB2312
GBK
IBM-Thai
IBM00858
IBM01140
IBM01141
IBM01142
IBM01143
IBM01144
IBM01145
IBM01146
IBM01147
IBM01148
IBM01149
IBM037
IBM1026
IBM1047
IBM273
IBM277
IBM278
IBM280
IBM284
IBM285
IBM290
IBM297
IBM420
IBM424
IBM437
IBM500
IBM775
IBM850
IBM852
IBM855
IBM857
IBM860
IBM861
IBM862
IBM863
IBM864
IBM865
IBM866
IBM868
IBM869
IBM870
IBM871
IBM918
ISO-2022-CN
ISO-2022-JP
ISO-2022-JP-2
ISO-2022-KR
ISO-8859-1
ISO-8859-13
ISO-8859-15
ISO-8859-2
ISO-8859-3
ISO-8859-4
ISO-8859-5
ISO-8859-6
ISO-8859-7
ISO-8859-8
ISO-8859-9
JIS_X0201
JIS_X0212-1990
KOI8-R
KOI8-U
Shift_JIS
TIS-620
US-ASCII
UTF-16
UTF-16BE
UTF-16LE
UTF-32
UTF-32BE
UTF-32LE
UTF-8
windows-1250
windows-1251
windows-1252
windows-1253
windows-1254
windows-1255
windows-1256
windows-1257
windows-1258
windows-31j
x-Big5-HKSCS-2001
x-Big5-Solaris
x-COMPOUND_TEXT
x-euc-jp-linux
x-EUC-TW
x-eucJP-Open
x-IBM1006
x-IBM1025
x-IBM1046
x-IBM1097
x-IBM1098
x-IBM1112
x-IBM1122
x-IBM1123
x-IBM1124
x-IBM1166
x-IBM1364
x-IBM1381
x-IBM1383
x-IBM300
x-IBM33722
x-IBM737
x-IBM833
x-IBM834
x-IBM856
x-IBM874
x-IBM875
x-IBM921
x-IBM922
x-IBM930
x-IBM933
x-IBM935
x-IBM937
x-IBM939
x-IBM942
x-IBM942C
x-IBM943
x-IBM943C
x-IBM948
x-IBM949
x-IBM949C
x-IBM950
x-IBM964
x-IBM970
x-ISCII91
x-ISO-2022-CN-CNS
x-ISO-2022-CN-GB
x-iso-8859-11
x-JIS0208
x-JISAutoDetect
x-Johab
x-MacArabic
x-MacCentralEurope
x-MacCroatian
x-MacCyrillic
x-MacDingbat
x-MacGreek
x-MacHebrew
x-MacIceland
x-MacRoman
x-MacRomania
x-MacSymbol
x-MacThai
x-MacTurkish
x-MacUkraine
x-MS932_0213
x-MS950-HKSCS
x-MS950-HKSCS-XP
x-mswin-936
x-PCK
x-SJIS_0213
x-UTF-16LE-BOM
X-UTF-32BE-BOM
X-UTF-32LE-BOM
x-windows-50220
x-windows-50221
x-windows-874
x-windows-949
x-windows-950
x-windows-iso2022jp
searchString after decoding=??

The ?? не из-за окна терминала, так как оба были взяты из одного терминала замазки со всеми соответствующими настройками. ?? затем передается в jdbctemplate, который возвращает 0 результатов в системе 2, в то время как в системе 1 мы получаем ожидаемый результат. Каково возможное решение для обеспечения согласованности декодирования во всех системах?

1 Ответ

0 голосов
/ 25 февраля 2020

Как указано в одном из комментариев, ваша проблема, вероятно, связана с использованием System.out(). Переменная System.out() представляет собой PrintStream, которая может использовать кодировку JVM по умолчанию, которая может быть или не быть UTF-8. См. Неразрешенную ошибку OpenJDK JDK-8187041. Используйте UTF-8 в качестве Charset по умолчанию для получения дополнительной информации об этом. Сводка этого отчета об ошибках (с моим акцентом):

Использование UTF-8 в качестве кодировки по умолчанию для виртуальной машины Java , чтобы API, зависящие от кодировки по умолчанию, работали согласованно во всех все платформы .

Также см. Вопрос SO Кодировка символов по умолчанию для java вывод на консоль .

Также обратите внимание, что данные локали для ваших двух систем различны. Например: LANG=en_GB.UTF-8 в системе, где японские символы отображаются правильно, по сравнению с LANG=en_GB в системе, где японские символы отображаются неправильно.

Во избежание потенциальной проблемы JVM в одной системе по умолчанию не используется кодировка UTF-8, просто создайте свой собственный PrintStream для вывода, который явно использует UTF-8:

import java.io.PrintStream;
import java.nio.charset.StandardCharsets;

...

    // Write the output to a UTF-8 PrintStream:
    PrintStream ps = new PrintStream(System.out, true, StandardCharsets.UTF_8.name());
    ps.println("java native array :: ");
    // etc...

Примечания:

  • Создание UTF-8 Строка в порядке, но сама по себе она не дает никакой гарантии, что она будет правильно отображаться.
  • Одно из утверждений, которые записал ваш код, было loaded charset is utf-8:: true, но оно записывалось только true, потому что Charset.isSupported("UTF-8") вернул true. Поддержка специфицированной c кодировки ничего не говорит о том, используется ли (или " загружено ", чтобы заимствовать ваш термин). Как показал ваш вывод, у вас были десятки поддерживаемых кодировок. Важным моментом является использование UTF-8 для рендеринга японских символов.

Если изменение вызовов println() не решает вашу проблему, пожалуйста, обновите ваш вопрос соответствующим образом.

...