8

采取以下情况:

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?

4

2 回答 2

8

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

  1. 如果媒体类型是application/xmlapplication/xml-external-parsed-entityapplication/xml-dtd或不是text/...类型但以 结尾,则使用 XML 序言的属性中+xml指定的字符集。encoding如果未指定字符集,则使用 UTF-8。

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

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

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

    湾。否则ISO-8859-1使用。

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

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

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

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

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

于 2013-09-16T16:31:13.660 回答
4

你可以这样做:

var
  sstream: TStringStream;
begin
  sstream := TStringStream.Create('', TEncoding.UTF8);
  try
    IdHttp.Post(MyUrL, AStream, sstream);
    DoSomethingWith(sstream.DataString);
  finally
    sstream.Free;
  end;
于 2013-09-16T16:01:54.387 回答