POST响应的TIdHTTP字符编码

时间:2013-09-16 15:43:00

标签: delphi unicode utf-8 delphi-xe idhttp

采取以下情况:

procedure Test;

var
 Response : String;

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

现在,网络服务器以UTF-8返回数据。 假设它返回一些包含字符é的UTF-8 XML。 如果我使用变量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 个答案:

答案 0 :(得分:7)

如果您使用的是最新版本的Indy 10,那么返回TIdHTTP.Post() String的重载版本会将数据解码为Unicode,但是用于解码的实际字符集取决于HTTP Content-Type响应头指定的媒体类型:

  1. 如果媒体类型为application/xmlapplication/xml-external-parsed-entityapplication/xml-dtd,或者不是text/...类型,但以+xml结尾,然后使用XML的prolog的encoding属性中指定的charset。如果未指定charset,则使用UTF-8。

  2. 否则,如果Content-Type响应标头指定了字符集,则使用它。

  3. 否则,如果媒体类型是text/...类型,则:

    一个。如果媒体类型为text/xmltext/xml-external-parsed-entity或以+xml结尾,则使用us-ascii

    湾否则使用ISO-8859-1

  4. 否则,使用Indy的默认编码(默认为ASCII)。

  5. 如果没有看到实际的HTTP Content-Type标头,很难知道您的情况属于哪种情况。听起来它正在落入#2或#3b,如果正在使用ISO-8859-1或类似的字符集,它将解释按原样返回的UTF-8字节值。

    UTF8ToString()需要UTF-8编码的RawByteString作为输入,但您传递的是UTF-16编码的UnicodeString。在这种情况下,RTL将执行UTF16-> Ansi转换,使用默认的Ansi字符集进行转换。这就是你得到编译器警告的原因,因为这样的转换可能会丢失数据。

    XML实际上是一种二进制数据格式,受charset编码的限制。 XML解析器需要知道XML的编码是什么,并且能够相应地解析原始编码的字节。这就是XML在XML序言中具有明确的encoding属性的原因。但是,当TIdHTTP将XML作为String下载时,虽然它会自动将其解码为Unicode,但 却相应地更新了XML的序言。

    真正的解决方案是首先不要将XML下载为String。请将其作为TStream下载(TMemoryStream是比TStringStream更好的选择),这样您的XML解析器就可以访问原始字节,原始字符集声明等。您可以传递{例如{1}}到TStream方法。

答案 1 :(得分:3)

你可以这样做:

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