Server-Sent Events (SSE) — это технология, позволяющая серверу отправлять клиенту события через HTTP-соединение. В Delphi для работы с SSE можно использовать компоненты TIdHTTP из библиотеки Indy. Однако одна из распространённых проблем — автоматический разрыв соединения каждые 330 секунд (5,5 минут) из-за таймаута по умолчанию.
В этой статье рассмотрим, как правильно завершить HTTP GET запрос для SSE вручную и избежать нежелательных разрывов соединения.
Проблема: HTTP GET запрос не завершается или обрывается через 330 секунд
При использовании TIdHTTP для SSE-соединений соединение может зависать или автоматически обрываться из-за таймаута по умолчанию в Indy. Это особенно критично, если клиенту нужно немедленно прекратить получение событий без ожидания таймаута.
Здесь метод Get блокирует выполнение до завершения соединения, которое может длиться бесконечно или прерваться по таймауту.
Решение 1: Использование асинхронного запроса с возможностью отмены
Для немедленного завершения запроса можно использовать асинхронный подход с фоновым потоком и механизмом принудительного прерывания.
Модифицированный пример:
uses
IdHTTP, IdGlobal, Classes, SysUtils;
type
TSSEClientThread = class(TThread)
private
FHTTP: TIdHTTP;
FURL: string;
FTerminateEvent: TEvent;
protected
procedure Execute; override;
public
constructor Create(const AURL: string);
destructor Destroy; override;
procedure TerminateRequest;
end;
constructor TSSEClientThread.Create(const AURL: string);
begin
inherited Create(True);
FURL := AURL;
FHTTP := TIdHTTP.Create(nil);
FHTTP.Request.Accept := 'text/event-stream';
FTerminateEvent := TEvent.Create(nil, True, False, '');
end;
destructor TSSEClientThread.Destroy;
begin
FHTTP.Free;
FTerminateEvent.Free;
inherited Destroy;
end;
procedure TSSEClientThread.Execute;
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
try
FHTTP.Get(FURL, Stream);
except
on E: EIdHTTPProtocolException do
if E.ErrorCode <> 200 then
raise;
end;
finally
Stream.Free;
end;
end;
procedure TSSEClientThread.TerminateRequest;
begin
if Assigned(FHTTP) then
FHTTP.Disconnect; // Принудительно разрываем соединение
FTerminateEvent.SetEvent;
Terminate;
end;
Использование:
var
SSEClient: TSSEClientThread;
procedure TForm1.StartSSE;
begin
SSEClient := TSSEClientThread.Create('http://example.com/sse');
SSEClient.Start;
end;
procedure TForm1.StopSSE;
begin
if Assigned(SSEClient) then
begin
SSEClient.TerminateRequest;
SSEClient.WaitFor;
FreeAndNil(SSEClient);
end;
end;
Этот подход позволяет корректно завершить запрос по требованию.
Решение 2: Использование TIdTCPClient вместо TIdHTTP
Если требуется более низкоуровневое управление соединением, можно использовать TIdTCPClient:
procedure TForm1.HandleSSEWithTCPClient;
var
TCPClient: TIdTCPClient;
Response: string;
begin
TCPClient := TIdTCPClient.Create(nil);
try
TCPClient.Host := 'example.com';
TCPClient.Port := 80;
TCPClient.Connect;
TCPClient.IOHandler.WriteLn('GET /sse HTTP/1.1');
TCPClient.IOHandler.WriteLn('Accept: text/event-stream');
TCPClient.IOHandler.WriteLn('Host: example.com');
TCPClient.IOHandler.WriteLn('Connection: keep-alive');
TCPClient.IOHandler.WriteLn('');
while not Application.Terminated do
begin
Response := TCPClient.IOHandler.ReadLn;
if Response = '' then Break;
// Обработка события...
end;
finally
TCPClient.Disconnect;
TCPClient.Free;
end;
end;
Преимущества:
Полный контроль над соединением.
Можно вручную разорвать соединение в любой момент.
Альтернативное решение: Использование WebSocket
Если SSE вызывает проблемы с управлением соединением, стоит рассмотреть WebSocket (TIdWebSocketClient), который предоставляет более гибкий двусторонний обмен данными.
Заключение
Для немедленного завершения HTTP GET запроса в Delphi при работе с Server-Sent Events можно:
1. Использовать асинхронный запрос с возможностью принудительного разрыва (TIdHTTP + поток).
2. Перейти на низкоуровневый TIdTCPClient для ручного управления.
3. Рассмотреть WebSocket как альтернативу SSE.
Выбор метода зависит от требований к гибкости и стабильности соединения.
Если у вас есть вопросы или дополнительные решения — делитесь в комментариях!
Статья объясняет, как принудительно завершить HTTP GET запрос для Server-Sent Events в Delphi, используя асинхронные методы или низкоуровневые TCP-подключения.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.