Кодировка символов TIdHTTP ответа POST

возьмем следующую ситуацию:

procedure Test;

var
 Response : String;

begin
 Response := IdHttp.Post(MyUrL, AStream);
 DoSomethingWith(Response);
end;

теперь веб-сервер возвращает мне данные в UTF-8. Предположим, он возвращает мне некоторый XML UTF-8, содержащий символ é. Если я использую переменную Response, она не содержит этого символа, но это вариант UTF-8 (#C3#A9), поэтому Indy не декодировал?

теперь я знаю, как решить эту проблему:

procedure Test;

var
 Response : String;

begin
 Response := UTF8ToString(IdHttp.Post(MyUrL, AStream));
 DoSomethingWith(Response);
end;

одно предостережение с этим решением: Delphi вызывает предупреждение W1058 (неявное приведение строки с потенциальной потерей данных из 'string' в 'RawByteString')

мой вопрос: это правильный способ справиться с этой проблемой или я могу поручить TIdHTTP сделать преобразование в UnicodeString для меня?

2 ответов


если вы используете последнюю версию Indy 10, то перегруженная версия TIdHTTP.Post() что возвращает String тут декодируйте данные в Unicode, однако фактическая кодировка, используемая для декодирования, зависит от типа носителя HTTP Content-Type заголовок ответа указывает:

  1. если тип носителя либо application/xml, application/xml-external-parsed-entity, application/xml-dtd или не text/... тип, но заканчивается на +xml, затем кодировка, указанная в encoding используется атрибут пролога XML. Если кодировка не указана, используется UTF-8.

  2. в противном случае, если Content-Type заголовок ответа задает кодировку, затем она используется.

  3. в противном случае, если тип носителя-это text/... тип, то:

    a. если тип носителя text/xml, text/xml-external-parsed-entity и заканчивается +xml, потом это.

    б. в противном случае ISO-8859-1 is используемый.

  4. в противном случае используется кодировка Indy по умолчанию (ASCII по умолчанию).

не видя фактического HTTP Content-Type заголовок, трудно понять, в какое состояние попадает ваша ситуация. Похоже, что он попадает в #2 или #3b, что объясняет байтовые значения UTF-8, возвращаемые как есть, если ISO-8859-1 или используется аналогичная кодировка.

UTF8ToString() ожидает кодировку UTF-8 RawByteString как вход, но вы передаете ему кодировку UTF-16 UnicodeString вместо. RTL будет выполнять преобразование UTF16 - >Ansi в этой ситуации, используя кодировку Ansi по умолчанию для преобразования. Вот почему вы получаете предупреждение компилятора, потому что такое преобразование может потерять данные.

XML-это действительно двоичный формат данных с учетом кодировок кодировок. Синтаксический анализатор XML должен знать, что такое кодировка XML, и иметь возможность анализировать необработанные закодированные байты соответственно. Вот почему XML имеет явное encoding атрибут прямо в XML-пролог. Однако, когда TIdHTTP загружает XML как String, хотя он автоматически декодирует его в Unicode, он не но обновите пролог XML соответственно.

реальное решение - не загружать XML как String в первую очередь. Загрузите его как TStream вместо (TMemoryStream лучше, чем TStringStream) таким образом, ваш синтаксический анализатор XML имеет доступ к исходным байтам, оригинальному объявлению кодировки и т. д. Вы можете пройти TStream до TXMLDocument.LoadFromStream() метод, например.


вы можете сделать это:

var
  sstream: TStringStream;
begin
  sstream := TStringStream.Create('', TEncoding.UTF8);
  try
    IdHttp.Post(MyUrL, AStream, sstream);
    DoSomethingWith(sstream.DataString);
  finally
    sstream.Free;
  end;