Indy HTTPServer и UTF8 и CP1251 проблема конвертации

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Ответить
jsa
постоялец
Сообщения: 295
Зарегистрирован: 28.11.2017 12:46:04

Indy HTTPServer и UTF8 и CP1251 проблема конвертации

Сообщение jsa »

Здравствуйте.
Написал простой REST сервер который работает через Indy компоненты. И выдает данные из MS SQL сервера

Проблема с кодировкой.
Ответ Response выдается в кодировке CP1251 чего бы я не делал

Код: Выделить всё

var rResponce: widestring;    
thr_Query: TSQLQuery;  <<<---- помещается запрос и выполняется Open, возвращается 1 запись с кодом и строкой XML

....

AResponseInfo.ContentType:='text/xml;charset='+Response_charset+';'  
AResponseInfo.ResponseNo := thr_Query.Fields.Fields[1].AsInteger;  

rResponce:=thr_Query.Fields.Fields[0].AsWideString;
AResponseInfo.ContentLength := length( rResponce );   

AResponseInfo.ContentText := rResponce; <<<---- Заменяемая строка

MemoLog.Lines.Add( rResponce ); 
Append(FLOG); Writeln(FLOG, rResponce); Close(FLOG);  

...
В целом REST работает нормально, выдает ответы на запросы в JSON или XML , но строки на кириллице выдаются не правильно.
Например в тестовом запросе выдается XML где есть слова "врач-терапевт"
Дальше я перебираю варианты функций перекодировки, и смотрю результаты
1. в ответе запроса в ARC клиента
2. в Memo поле в REST сервере (да, пока это не в виде службы сделано)
3. файле лога

Код: Выделить всё

----------------

...
AResponseInfo.ContentText := rResponce; 
...

ARC-client 
врач-терапевт

Memo и файл txt 
врач-терапевт

-----------------

...
AResponseInfo.ContentText := UTF8ToWinCP(rResponce);  
... 
 
ARC-client 
врач-терапевт

Memo и файл txt 
врач-терапевт

-----------------

...
AResponseInfo.ContentText := WinCPtoUTF8(rResponce);  
...
 
ARC-client 		   
врач-терапевт   

Memo и файл txt 
врач-терапевт

-----------------

...
rResponce := WinCPtoUTF8(rResponce);
AResponseInfo.ContentText := rResponce;
...

ARC-client 
врач-терапевт

Memo и файл txt 
врач-терапевт

-----------------

...
rResponce := UTF8toWinCP(rResponce);
AResponseInfo.ContentText := rResponce;

ARC-client 
пїЅпїЅпїЅпїЅ-пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ

Memo и файл txt 
????-????????  а в файле ����-��������

-----------------
var rResponce: string;  // т.е. поменял widestring на string
...
rResponce := UTF8toWinCP(rResponce);
AResponseInfo.ContentText := rResponce;

ARC-client 
врач-терапевт

Memo и файл txt 
????-????????  а в файле ����-��������

-----------------
А под конец обнаружил, что в тех случаях когда в ARC-client строка отображается нормально (врач-терапевт)
, то это скорее делает с ама программа ARC , и так отображается только при выполнении запроса.
Если же закрыть вкладку запроса и открыть ее из истории то там результат уже отображается (????-????????)

Я уже не знаю что с этим делать и как побороть?
Как сделать нормальную выдачу ответа в UTF8 как положено?
wwswowsogon
постоялец
Сообщения: 157
Зарегистрирован: 23.12.2008 19:41:37

Сообщение wwswowsogon »

Можете здесь посмотреть: http://freepascal.ru/forum/viewtopic.php?f=5&t=43051, обсуждалось недавно нечто подобное, сам долго мучился, потом решил вопрос вот так:

Код: Выделить всё


emmsg.Body.Text := UTF8ToWinCP(emtext);

jsa
постоялец
Сообщения: 295
Зарегистрирован: 28.11.2017 12:46:04

Сообщение jsa »

wwswowsogon писал(а):Можете здесь посмотреть: http://freepascal.ru/forum/viewtopic.php?f=5&t=43051, обсуждалось недавно нечто подобное, сам долго мучился, потом решил вопрос вот так:

Код: Выделить всё

emmsg.Body.Text := UTF8ToWinCP(emtext);
Спасибо за ответ. Этот вариант UTF8ToWinCP тоже перечислен в примерах которые я привел.
Даже 2 раза с переменной типа widestring и переменной типа string
Визуально этот вариант вроде бы работает но ОЧЕНЬ странно (я написал в конце своего первого сообщения), и получатели ответа сообщают, что на самом деле кодировка cp1251 остается

P.S. кстати ту тему тоже я открывал :)
delphius
постоялец
Сообщения: 131
Зарегистрирован: 18.03.2020 12:40:11

Сообщение delphius »

jsa писал(а):Как сделать нормальную выдачу ответа в UTF8 как положено?
Возможное решение
jsa
постоялец
Сообщения: 295
Зарегистрирован: 28.11.2017 12:46:04

Сообщение jsa »

delphius писал(а):
jsa писал(а):Как сделать нормальную выдачу ответа в UTF8 как положено?
Возможное решение
Спасибо большое.

Код: Выделить всё

var rResponce: widestring; 
...
rResponse:=thr_Query.Fields.Fields[0].AsString; 
...
AResponseInfo.ContentText := rResponse;
AContext.Connection.IOHandler.DefAnsiEncoding := IndyUTF8Encoding;    
Отрабатывает так же как и в случае с UTF8ToWinCP
но по сравнению с этой командой хотябы логично выглядят пояснения и сама команда.
Посмотрим, что скажут те кто шлет запрос.

Добавлено спустя 1 час 44 минуты 54 секунды:
В общем такой способ тоже не работает.
сделал простой метод/функцию /test_encode

В ARC выдается результат
[{"LAT":"This is a test message to check the encoding","RUS":"Это тестовое сообщение для проверки кодировки","len":120}]

А в любом браузере
[{"LAT":"This is a test message to check the encoding","RUS":"Это тестовое сообщение для пров
т.е. оно кракозябрами да еще и оборвано из-за неверного подсчета длины контента
бедааа

Добавлено спустя 44 минуты 11 секунд:
проверяю тут https://involta.ru/tools/decoder/
в разделе "Определить исходную кодировку"
Браузер действительно получает cp1251

P.S. Заменил AResponseInfo.ContentLength := length( rResponse );
на AResponseInfo.ContentLength := -1; пусть индеец сам считает длину, насчитал 160 вместо 120
теперь в браузере вижу
[{"len":120,"LAT":"This is a test message to check the encoding","RUS":"Это тестовое сообщение для проверки кодировки"}]

Добавлено спустя 1 час 55 минут 27 секунд:
----

Тааак.
Вот тут почитал что народ пишет.

По пробовал через поток, получилась ерунда, к тому же не получилось никак вычислить правильно длину сообщения для передачи в поток влепил просто 150, но это не годится.

Код: Выделить всё

           AResponseInfo.ContentStream := TMemoryStream.Create;
           try
              AResponseInfo.ContentStream.Write(Pointer(rResponse)^, 150);
              AResponseInfo.ContentStream.Position := 0;
              AResponseInfo.WriteContent;
           finally
           AResponseInfo.ContentStream := nil;
           end;  
Эта схема работает если rResponse : string;

----

потом проверил что таки пишу в заголовки, и там был json вместо application/json , поставил второе и в браузерах кодировка стала нормально отображаться.
Это у меня работает совместно с

Код: Выделить всё

AResponseInfo.ContentText := rResponse;
AContext.Connection.IOHandler.DefAnsiEncoding := IndyUTF8Encoding;  

о чем я написал выше.


Теперь надо забороть выдачу и в формате xml , там помоему сервис который шлет запрос не принимает заголовок application/xml пришлось поставить text/xml , сейчас еще потыкаю тот сервис.
Ответить