procedure Test; var Response : String; begin Response := IdHttp.Post(MyUrL,AStream); DoSomethingWith(Response); end;
现在,web服务器以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?
解决方法
>如果媒体类型是application / xml,application / xml-external-parsed-entity,application / xml-dtd,或者不是text / …类型但以xml结尾,那么编码中指定的charset使用XML的prolog属性.如果未指定charset,则使用UTF-8.
>否则,如果Content-Type响应头指定了charset,则使用它.
>否则,如果媒体类型是text / …类型,则:
一个.如果媒体类型是text / xml,text / xml-external-parsed-entity,或以xml结尾,则使用us-ascii.
湾否则使用ISO-8859-1.
>否则,使用Indy的默认编码(默认为ASCII).
如果没有看到实际的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 prolog中具有明确的编码属性.但是,当TIdHTTP将XML作为字符串下载时,虽然它会自动将其解码为Unicode,但它还没有相应地更新XML的序言.
真正的解决方案是首先不要将XML作为String下载.将其作为TStream下载(TMemoryStream是比TStringStream更好的选择),因此您的XML解析器可以访问原始字节,原始字符集声明等.例如,您可以将TStream传递给TXMLDocument.LoadFromStream()方法.