我需要使用 Indy 10 HTTP 服务器发送 UTF-8 编码的响应,其中包含特殊字符(如
ő
和 á
)。原来的程序是用Indy 9编写的,没有问题,但是根据Remy Lebeau的说法:
在 Delphi 2009 之前的版本中,Indy 10 将在内部执行转换 如果指定 Ansi 和 Byte 编码,则从 AnsiString 到 UTF-16 到 Bytes 是不同的。在该转换期间,如果字节编码是 Indy8BitEncoding, U+00FF 以上的 UTF-16 代码单元将转换为“?”人物。 为了 要按原样发送 AnsiString,您必须设置 Ansi 和 Byte 编码 到同一个 TIdTextEncoding 对象。
但我找不到正确的方法。 HTTP 服务器的 IOHandler 没有 DefStringEncoding 属性,因此我尝试了以下对话,但没有成功:
AResponseInfo.ContentEncoding:='utf8';
AResponseInfo.ContentType:='text/html';
ss:=TStringStream.Create('ő');
ss.WriteString(' '+AnsiString('ő'));
ss.WriteString(' '+WideString('ő'));
ss.WriteString(' '+AnsiToUtf8('ő'));
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_8Bit, IndyTextEncoding_8Bit)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_Default, IndyTextEncoding_8Bit)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_ASCII, IndyTextEncoding_8Bit)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_UTF16BE, IndyTextEncoding_8Bit)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_UTF16LE, IndyTextEncoding_8Bit)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_UTF7, IndyTextEncoding_8Bit)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_UTF8, IndyTextEncoding_8Bit)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_8Bit, IndyTextEncoding_UTF8)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_Default, IndyTextEncoding_UTF8)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_ASCII, IndyTextEncoding_UTF8)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_UTF16BE, IndyTextEncoding_UTF8)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_UTF16LE, IndyTextEncoding_UTF8)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_UTF7, IndyTextEncoding_UTF8)+' ';
ss.Seek(0, 0);
AResponseInfo.ContentText:=AResponseInfo.ContentText+ReadStringFromStream(ss, -1, IndyTextEncoding_UTF8, IndyTextEncoding_UTF8)+' ';
我得到了以下回复:
? ? ?? ? ? ?? ??? ??? o o L' ? ? ? Aµ Aµ A.Â' dz? dz? dz?dz? dz? dz? dz?dz? ⃵⃵âƒ. d" d" e" Aµ Aµ A.Â' o o L'
最接近的是
o
,但缺少重音。 L'
似乎也很有希望,因为 ő
是 UTF-8 字节中的 Ĺ‘
,但它也不完全相同。
我该如何解决这个问题?
更新
如果我将
AResponseInfo.CharSet
设置为 UTF-8
,然后将 ContentText
设置为 ANSI 中所需的字符串(不转换为任何内容),它就可以工作。
但现在我面临另一个问题,当我的
ContentText
已经是UTF-8时,Indy 10会尝试再次将其转换为UTF-8。因为我无法设置 DefStringEncoding
,因为它在这里不可用,所以我无法让 Indy 10 跳过对话。唯一的解决方法是将 UTF-8 字符串转换回 ANSI,然后让 Indy 再次将其转换为 UTF-8。
HTTP 服务器的 IOHandler 没有 DefStringEncoding 属性...我无法设置 DefStringEncoding,因为它在这里不可用
是的,可以使用。 它是连接
IOHandler
的属性,而不是服务器IOHandler
的属性。
AResponseInfo.ContentType := 'text/html';
AResponseInfo.Charset := 'utf-8';
AResponseInfo.ContentText := Utf8Encode('ő');
AContext.Connection.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8;
AContext.Connection.IOHandler.DefAnsiEncoding := IndyTextEncoding_UTF8;
话虽这么说,一个更简单的解决方案是将 UTF-8 内容放入
TStream
中,然后使用 AResponseInfo.ContentStream
而不是 AResponseInfo.ContentText
。
AResponseInfo.ContentType := 'text/html';
AResponseInfo.Charset := 'utf-8';
AResponseInfo.ContentStream := TStringStream.Create(Utf8Encode('ő'));