我正在使用带有Indy 10.6.2.5459的Delphi 7向服务器发出POST
请求。除了EIdHTTPProtocolException
发生时的响应编码外,它一切正常。
当我没有引发EIdHTTPProtocolException
时,我可以像这样解码响应以正确获取特殊字符:
responseBody := '';
responseContent := TStringStream.Create('');
try
try
IdHTTP.Post(GetUrlMetodo(ASngpcCloudRequest.Tipo), requestBody, responseContent);
responseBody := UTF8Decode(responseContent.DataString);
except
on E: EIdHTTPProtocolException do
responseBody := UTF8Decode(E.ErrorMessage);
end;
finally
FreeAndNil(responseContent);
end;
但是,当引发EIdHTTPProtocolException
时,即使使用E.ErrorMessage
,?
属性也会UTF8Decode()
而不是预期的特殊字符。
那么,我如何正确解码E.ErrorMessage
?
答案 0 :(得分:4)
由于您使用的是Delphi 7,因此本地string
类型为AnsiString
,这一点非常重要,因为这意味着Indy在解码字符串时必须做更多工作。
当TIdHTTP
将HTTP响应主体解析为string
时,它首先使用响应字符集解码为Unicode,如服务器报告的那样。例如,如果服务器以UTF-8编码发送响应,则需要在charset
标头的Content-Type
属性中指定该响应。
在Delphi / FreePascal的Unicode前版本中,然后将Unicode数据转换为ANSI以适合AnsiString
。在这些编译器版本中,返回TIdHTTP
的{{1}}方法具有可选的string
参数,以便您指定要转换为Unicode数据的ADestEncoding
编码。如果未指定,则使用Indy的默认编码,默认为US-ASCII(请参阅AnsiString
单元中的全局GIdDefaultTextEncoding
变量)。
你真的应该让Indy为你处理这个解码,因为不能保证任何给定的响应都是UTF-8编码的。但是,您可以指定您希望Indy的输出始终为UTF-8编码(仅限Unicode前版本),例如:
IdGlobal
如果您曾升级到Unicode版本的Delphi,那么您只需删除额外的UTF-8步骤:
try
responseBody := UTF8Decode(
IdHTTP.Post(GetUrlMetodo(ASngpcCloudRequest.Tipo), requestBody,
IndyTextEncoding_UTF8)
);
except
on E: EIdHTTPProtocolException do
responseBody := E.ErrorMessage;
end;
在您的问题中提供的示例中,您绕过try
responseBody := IdHTTP.Post(GetUrlMetodo(ASngpcCloudRequest.Tipo), requestBody);
except
on E: EIdHTTPProtocolException do
responseBody := E.ErrorMessage;
end;
的自动解码逻辑,将原始响应正文原样接收到TIdHTTP
而不是一个TStream
。在这种情况下,您负责确保检查响应string
以了解如何正确解码原始数据。它可能不总是UTF-8。 Indy具有charset
和ReadStringFromStream()
功能,可让您在从ReadStringAsCharset()
阅读string
时指定编码/字符集。
现在,为了回答您的问题,为什么不能正确解码TStream
?好吧,因为已经已经由EIdHTTPProtocolException.ErrorMessage
解码了
HOWEVER ,这就是问题 - 当解码错误响应以放入TIdHTTP
时,EIdHTTPProtocolException
参数当前不能从引发异常的代码中访问,因此使用Indy的默认编码,默认情况下是US-ASCII。这就是为什么你看到“特殊”字符转换为ADestEncoding
的原因(同样,这只会影响Delphi / FreePascal的Unicode前版本)。
您可以通过以下几种方法解决此问题:
在调用?
之前将全局IdGlobal.GIdDefaultTextEncoding
变量设置为encUTF8
。这样,如果引发Post()
,则其EIdHTTPProtocolException
将采用UTF-8编码。请注意,这确实会影响全局的Indy,并且在Unicode前版本的Delphi中比在Unicode版本中影响更大,因此请小心。
ErrorMessage
由于您要将成功和失败响应保存到同一个GIdDefaultTextEncoding := encUTF8;
...
try
...
responseBody := ...;
except
on E: EIdHTTPProtocolException do
responseBody := UTF8Decode(E.ErrorMessage);
end;
变量,因此您也可以完全禁用responseBody
,并删除EIdHTTPProtocolException
块。您可以在调用try/except
之前启用hoNoProtocolErrorException
属性中的hoWantProtocolErrorContent
和TIdHTTP.HTTPOptions
标记来执行此操作。您可以检查Post()
属性以区分成功和失败响应:
TIdHTTP.ResponseCode