Поскольку вы используете Delphi 7, собственный тип string
равен AnsiString
, что важно отметить, поскольку это означает, что Indy приходится выполнять больше работы при декодировании строк.
Когда TIdHTTP
анализируеттело ответа HTTP в string
, оно сначала декодируется в Unicode с использованием кодировки ответа, как сообщает сервер.Например, если сервер отправляет ответ в кодировке UTF-8, его необходимо указать в атрибуте charset
заголовка Content-Type
.
В версиях Delphi / FreePascal, предшествующих Unicode,эти данные Unicode затем преобразуются в ANSI, чтобы поместиться в AnsiString
.В этих версиях компилятора методы TIdHTTP
, которые возвращают string
, имеют необязательный параметр ADestEncoding
, позволяющий указать, в какую кодировку AnsiString
требуется преобразовать данные Unicode.Если не указано иное, используется кодировка Indy по умолчанию, которая по умолчанию является US-ASCII (см. Глобальную переменную GIdDefaultTextEncoding
в блоке IdGlobal
).
Вы действительно должны позволить Indy обработать это декодирование для вас,поскольку нет никакой гарантии, что любой данный ответ должен быть в кодировке UTF-8.Однако вы можете указать, что вы хотите, чтобы выход Indy всегда был в кодировке UTF-8 (только для версий, предшествующих Unicode), например:
try
responseBody := UTF8Decode(
IdHTTP.Post(GetUrlMetodo(ASngpcCloudRequest.Tipo), requestBody,
IndyTextEncoding_UTF8)
);
except
on E: EIdHTTPProtocolException do
responseBody := E.ErrorMessage;
end;
Если вы когда-либо обновитесь до версии Delphi с Unicode, вы можетезатем просто удалите лишний шаг UTF-8:
try
responseBody := IdHTTP.Post(GetUrlMetodo(ASngpcCloudRequest.Tipo), requestBody);
except
on E: EIdHTTPProtocolException do
responseBody := E.ErrorMessage;
end;
В примере, который вы предоставили в своем вопросе, вы обходите логику автоматического декодирования TIdHTTP
, получая необработанное тело ответа as- в TStream
вместо string
.В этом случае вы несете ответственность за проверку charset
ответа, чтобы знать, как правильно декодировать необработанные данные.Это не всегда может быть UTF-8.Indy имеет функции ReadStringFromStream()
и ReadStringAsCharset()
, которые позволяют указывать кодировку / кодировку при чтении string
из TStream
.
Теперь, чтобы ответить на ваш вопрос, почему вы не можете декодироватьEIdHTTPProtocolException.ErrorMessage
правильно?Ну, поскольку он уже был декодирован для вас TIdHTTP
.
HOWEVER , вот в чем проблема - при декодировании ответа об ошибке для помещения в EIdHTTPProtocolException
, параметр ADestEncoding
в настоящее время НЕ доступен из кода, который вызывает исключение, поэтому вместо него используется стандартная кодировка Indy, которая по умолчанию является US-ASCII.Вот почему вы видите, что «специальные» символы преобразуются в ?
(опять же, это влияет только на версии Delphi / FreePascal, предшествующие Unicode).
У вас есть несколько вариантов решения этой проблемы:
установите глобальную переменную IdGlobal.GIdDefaultTextEncoding
на encUTF8
перед вызовом Post()
.Таким образом, если EIdHTTPProtocolException
поднят, его ErrorMessage
будет закодирован в UTF-8.Обратите внимание, что это влияет на Indy глобально и оказывает гораздо большее влияние в версиях Delphi до Unicode, чем в версиях Unicode, поэтому будьте осторожны с ним.
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
, чтобы различать успешные и неудачные ответы:
IdHTTP.HTTPOptions := IdHTTP.HTTPOptions + [hoNoProtocolErrorException, hoWantProtocolErrorContent];
responseBody := UTF8Decode(
IdHTTP.Post(GetUrlMetodo(ASngpcCloudRequest.Tipo), requestBody,
IndyTextEncoding_UTF8)
);