При работе с HTTP запросами в Delphi, используя компонент TIdHTTP из библиотеки Indy, часто возникает ситуация, когда сервер возвращает ошибку, например, 400 Bad Request. При этом, сервер может передавать полезную информацию об ошибке в теле ответа (например, в формате JSON), которую необходимо получить для дальнейшей обработки. Однако, по умолчанию TIdHTTP генерирует исключение EIdHTTPProtocolException, и прямой доступ к телу ответа становится затруднительным, особенно если кодировка ответа отличается от ожидаемой.
Проблема:
При получении ошибки 400 Bad Request, TIdHTTP выбрасывает исключение EIdHTTPProtocolException. При этом, тело ответа сервера, содержащее полезную информацию, может быть недоступно или искажено из-за проблем с кодировкой. Свойство ErrorMessage исключения может содержать информацию, но национальные символы в ней могут быть потеряны. ssResponse и IdHTTP.Response.ContentStream оказываются пустыми.
Решение 1: Отключение исключения и получение тела ответа
Наиболее эффективным решением является отключение автоматической генерации исключения EIdHTTPProtocolException и явное получение тела ответа. Для этого необходимо настроить свойства HTTPOptions компонента TIdHTTP:
Отключение исключения: Установите флаг hoNoProtocolErrorException в свойстве TIdHTTP.HTTPOptions. Это предотвратит генерацию исключения при получении HTTP-ответа с кодом ошибки.
Получение тела ответа: Установите флаг hoWantProtocolErrorContent в свойстве TIdHTTP.HTTPOptions. Это укажет TIdHTTP сохранять тело ответа даже при ошибке.
После этого, можно проверять код ответа IdHTTP.ResponseCode после выполнения запроса Post и, если он указывает на ошибку (например, 400), читать тело ответа из TStream.
Пример кода:
uses
IdHTTP, IdGlobal, Classes;
procedure TForm1.Button1Click(Sender: TObject);
var
IdHTTP: TIdHTTP;
ssRequest, ssResponse: TStringStream;
fullUrl: string;
begin
IdHTTP := TIdHTTP.Create(nil);
try
IdHTTP.HTTPOptions := [hoNoProtocolErrorException, hoWantProtocolErrorContent];
ssRequest := TStringStream.Create('{"key": "value"}', TEncoding.UTF8); // Пример тела запроса
ssResponse := TStringStream.Create(''); // Создаем пустой стрим для ответа
fullUrl := 'https://example.com/api/endpoint'; // Замените на ваш URL
try
IdHTTP.Post(fullUrl, ssRequest, ssResponse);
if IdHTTP.ResponseCode = 400 then
begin
// Обработка ошибки 400
ssResponse.Position := 0; // Возвращаемся в начало стрима
ShowMessage('Ошибка 400: ' + ssResponse.DataString); // Выводим тело ответа
// Здесь можно распарсить JSON, если ответ в формате JSON
end
else
begin
// Обработка успешного ответа
ssResponse.Position := 0;
ShowMessage('Успех: ' + ssResponse.DataString);
end;
except
on E: Exception do
ShowMessage('Ошибка: ' + E.Message);
end;
finally
ssRequest.Free;
ssResponse.Free;
end;
finally
IdHTTP.Free;
end;
end;
Важно:
Убедитесь, что создаете TStringStream с правильной кодировкой (TEncoding.UTF8 в данном примере). Если кодировка ответа сервера отличается, необходимо использовать соответствующую кодировку. Иначе, при чтении DataString данные могут быть искажены.
После записи в TStringStream необходимо установить Position в 0, чтобы прочитать данные с начала стрима.
Альтернативное решение (использование перегруженной версии Post):
TIdHTTP имеет перегруженную версию метода Post, которая возвращает строку. Эта версия автоматически учитывает кодировку ответа при преобразовании байтов в строку.
uses
IdHTTP, IdGlobal;
procedure TForm1.Button1Click(Sender: TObject);
var
IdHTTP: TIdHTTP;
ssRequest: TStringStream;
fullUrl: string;
responseString: string;
begin
IdHTTP := TIdHTTP.Create(nil);
try
IdHTTP.HTTPOptions := [hoNoProtocolErrorException, hoWantProtocolErrorContent];
ssRequest := TStringStream.Create('{"key": "value"}', TEncoding.UTF8); // Пример тела запроса
fullUrl := 'https://example.com/api/endpoint'; // Замените на ваш URL
try
responseString := IdHTTP.Post(fullUrl, ssRequest);
if IdHTTP.ResponseCode = 400 then
begin
// Обработка ошибки 400
ShowMessage('Ошибка 400: ' + responseString); // Выводим тело ответа
// Здесь можно распарсить JSON, если ответ в формате JSON
end
else
begin
// Обработка успешного ответа
ShowMessage('Успех: ' + responseString);
end;
except
on E: Exception do
ShowMessage('Ошибка: ' + E.Message);
end;
finally
ssRequest.Free;
end;
finally
IdHTTP.Free;
end;
end;
В этом случае, вам не нужно создавать TStringStream для ответа, так как результат возвращается в виде строки. TIdHTTP самостоятельно определяет кодировку ответа и преобразует байты в строку корректно.
В заключение:
Оба представленных решения позволяют получить тело ответа сервера при возникновении ошибки 400 Bad Request. Выбор конкретного решения зависит от ваших предпочтений и требований к коду. Важно помнить о правильной обработке кодировок, чтобы избежать искажения данных. Использование перегруженной версии Post, возвращающей строку, может упростить код и избежать проблем с кодировкой, но требует включения hoNoProtocolErrorException и hoWantProtocolErrorContent.
Статья описывает методы получения полного ответа сервера, включая тело ответа, при возникновении ошибки 400 Bad Request при использовании TIdHTTP в Delphi, с акцентом на обработку кодировок.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.