Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Как немедленно завершить HTTP GET запрос для Server-Sent Events в Delphi и избежать разрыва соединения каждые 330 секунд

Delphi , Интернет и Сети , TCP/IP

 

Введение

Server-Sent Events (SSE) — это технология, позволяющая серверу отправлять клиенту события через HTTP-соединение. В Delphi для работы с SSE можно использовать компоненты TIdHTTP из библиотеки Indy. Однако одна из распространённых проблем — автоматический разрыв соединения каждые 330 секунд (5,5 минут) из-за таймаута по умолчанию.

В этой статье рассмотрим, как правильно завершить HTTP GET запрос для SSE вручную и избежать нежелательных разрывов соединения.


Проблема: HTTP GET запрос не завершается или обрывается через 330 секунд

При использовании TIdHTTP для SSE-соединений соединение может зависать или автоматически обрываться из-за таймаута по умолчанию в Indy. Это особенно критично, если клиенту нужно немедленно прекратить получение событий без ожидания таймаута.

Пример кода, который может привести к проблеме:

procedure TForm1.StartSSEClient;
var
  HTTP: TIdHTTP;
  Stream: TMemoryStream;
begin
  HTTP := TIdHTTP.Create(nil);
  Stream := TMemoryStream.Create;
  try
    HTTP.Request.Accept := 'text/event-stream';
    HTTP.Get('http://example.com/sse', Stream); // Блокирующий вызов
    // Обработка данных...
  finally
    Stream.Free;
    HTTP.Free;
  end;
end;

Здесь метод 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




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: TCP/IP ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-06-09 05:19:39/0.0035390853881836/0