Асинхронные HTTP-запросы в Delphi: ожидание результата без блокировки интерфейса
При работе с HTTP-запросами в многопоточной среде, важно уметь правильно организовывать асинхронные операции, чтобы интерфейс программы оставался отзывчивым для пользователя. В данной статье мы рассмотрим, как выполнить HTTP-запрос в фоновом потоке и получить его результат, не блокируя основной поток.
Проблема
Пользователь хочет показать форму ожидания ("Please wait...") поверх основного окна, выполнить HTTP-запросы (GET и POST) и закрыть форму ожидания после получения ответа от сервера. Поскольку HTTP-запрос обращается к физическому устройству и может занять некоторое время, выполнение запроса в фоновом потоке позволяет избежать "зависания" основного потока.
Решение
Для решения этой задачи можно использовать различные подходы, например, анонимные потоки или задачи (tasks). Ниже представлен пример кода, который демонстрирует использование анонимного потока с последующим ожиданием его завершения и получением результата.
function TForm1.Test: string;
var
MyThread: TThread;
Response: string;
begin
// Показываем форму ожидания
WaitForm.Label1.Caption := 'Please wait ...';
WaitForm.BitBtn1.Enabled := False;
WaitForm.FormStyle := fsStayOnTop;
WaitForm.Show;
// Создаем анонимный поток
MyThread := TThread.CreateAnonymousThread(
procedure
var
Http: TIdHTTP;
ReqStream: TStringStream;
Command, CommandName: string;
begin
// Здесь ваш код для выполнения HTTP-запроса
Command := '{"Amount":"69.00","TerminalName":"SIMULATE","omitSlipPrintingOnEFT":"1"}';
CommandName := 'sale';
Http := TIdHTTP.Create(nil);
try
// Настройка запроса
Http.Request.ContentType := 'application/json';
// ...
// Запись данных в поток
ReqStream := TStringStream.Create(Command, TEncoding.UTF8);
try
// Получение ответа от сервера
Response := Http.Post('http://localhost:5555/' + CommandName, ReqStream);
finally
ReqStream.Free;
end;
finally
Http.Free;
end;
end
);
try
// Установка свойства, чтобы поток не удалялся автоматически
MyThread.FreeOnTerminate := False;
// Запуск потока
MyThread.Start;
// Ожидание завершения потока
MyThread.WaitFor;
finally
// Закрытие формы ожидания
WaitForm.FormStyle := fsNormal;
WaitForm.BitBtn1.Enabled := True;
WaitForm.Close;
// Освобождение ресурсов потока
MyThread.Free;
end;
// Возвращаем результат
Result := Response;
end;
Альтернативное решение
В качестве альтернативы, можно использовать коллбэк для уведомления о завершении потока и получении результата. Пример коллбэка:
procedure TForm1.HandleResponse(const Response: string);
begin
// Здесь код для обработки полученного ответа
ShowMessage(Response);
end;
procedure TForm1.DoTest;
var
MyThread: TThread;
begin
// Создаем анонимный поток
MyThread := TThread.CreateAnonymousThread(
procedure
var
Http: TIdHTTP;
ReqStream: TStringStream;
Command, CommandName: string;
Response: string;
begin
// Ваш код для HTTP-запроса
// ...
// Получение ответа
Response := Http.Post('http://localhost:5555/' + CommandName, ReqStream);
// Вызов коллбэка в главном потоке
TThread.Queue(nil,
procedure
begin
Self.HandleResponse(Response);
end);
end
);
// Запускаем обработчик завершения потока
MyThread.OnTerminate := ThreadTerminated;
// Показываем форму ожидания
// ...
// Запускаем поток
MyThread.Start;
// Обработчик завершения потока
procedure TForm1.ThreadTerminated(Sender: TObject);
begin
// Закрытие формы ожидания
// ...
// Обработка возможных исключений
end;
// Обработка возможного исключения при запуске потока
except
ThreadTerminated(nil);
raise;
end;
end;
Важные замечания
Не забудьте закрыть форму ожидания после получения ответа от сервера.
Обратите внимание на обработку исключений в потоке и в коллбэке.
Рассмотрите использование компонента TIdAntiFreeze для предотвращения "зависания" интерфейса, если это уместно в вашем приложении.
Используя эти подходы, вы сможете организовать асинхронное выполнение HTTP-запросов, не блокируя основной поток программы, и предоставить пользователю удобный интерфейс, который остается отзывчивым в течение всего времени выполнения запроса.
**Контекст**: Обсуждение и демонстрация способов выполнения асинхронных HTTP-запросов в Delphi для ожидания результата без блокировки интерфейса.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.