How can I update HTML pages dynamically with Indy HTTP server using jQuery and "Long Polling"?
Asked Answered
J

1

7

I have read the article Simple Long Polling Example with JavaScript and jQuery. The paragraph "Long Polling - An Efficient Server-Push Technique" explains that

the Long Polling technique combines the best-case traditional polling with persistent remote server connections. The term Long Polling itself is short for long-held HTTP request.

How can I implement a Indy based HTTP server which uses Long Polling?

Jequirity answered 12/1, 2013 at 10:35 Comment(0)
J
6

Here is a self-contained example project, tested with Indy version 10.5.9 and Delphi 2009.

When the application runs, navigate to http://127.0.0.1:8080/. The server will then serve a HTML document (hard-coded in the OnCommandGet handler).

This document contains a div element which will be used as the container for new data:

<body>
  <div>Server time is: <div class="time"></div></div>'
</body>

The JavaScript code then send requests to the resource /getdata in a loop (function poll()).

The server responds with a HTML fragment which contains a new <div> element with the current server time. The JavaScript code then replaces the old <div> element with the new.

To simulate server work, the method waits for one second before returning the data.

program IndyLongPollingDemo;

{$APPTYPE CONSOLE}

uses
  IdHTTPServer, IdCustomHTTPServer, IdContext, IdSocketHandle, IdGlobal,
  SysUtils, Classes;

type
  TMyServer = class(TIdHTTPServer)
  public
    procedure InitComponent; override;
    procedure DoCommandGet(AContext: TIdContext;
      ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); override;
  end;

procedure Demo;
var
  Server: TMyServer;
begin
  Server := TMyServer.Create(nil);
  try
    try
      Server.Active := True;
    except
      on E: Exception do
      begin
        WriteLn(E.ClassName + ' ' + E.Message);
      end;
    end;
    WriteLn('Hit any key to terminate.');
    ReadLn;
  finally
    Server.Free;
  end;
end;

procedure TMyServer.InitComponent;
var
  Binding: TIdSocketHandle;
begin
  inherited;

  Bindings.Clear;
  Binding := Bindings.Add;
  Binding.IP := '127.0.0.1';
  Binding.Port := 8080;

  KeepAlive := True;
end;

procedure TMyServer.DoCommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
  AResponseInfo.ContentType := 'text/html';
  AResponseInfo.CharSet := 'UTF-8';

  if ARequestInfo.Document = '/' then
  begin
    AResponseInfo.ContentText :=
      '<html>' + #13#10
      + '<head>' + #13#10
      + '<title>Long Poll Example</title>' + #13#10
      + '  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript" charset="utf-8"> ' +
        #13#10
      + '  </script> ' + #13#10
      + '  <script type="text/javascript" charset="utf-8"> ' + #13#10
      + '  $(document).ready(function(){ ' + #13#10
      + '  (function poll(){' + #13#10
      + '  $.ajax({ url: "getdata", success: function(data){' + #13#10
      + '      $("div.time").replaceWith(data);' + #13#10
      + '  }, dataType: "html", complete: poll, timeout: 30000 });' + #13#10
      + '  })();' + #13#10
      + '  });' + #13#10
      + '  </script>' + #13#10
      + '</head>' + #13#10
      + '<body> ' + #13#10
      + '  <div>Server time is: <div class="time"></div></div>' + #13#10
      + '</body>' + #13#10
      + '</html>' + #13#10;
  end
  else
  begin
    Sleep(1000);
    AResponseInfo.ContentText := '<div class="time">'+DateTimeToStr(Now)+'</div>';
  end;
end;

begin
  Demo;
end.
Jequirity answered 12/1, 2013 at 10:38 Comment(1)
Instead of having TMyServer assign a handler to its own inherited OnCommandGet event, have it override the virtual TIdCustomHTTPServer.DoCommandGet() method instead. Also, set the Response.CharSet after setting the Response.ContentType rather than before. The ContentType property setter may (and in the future, likely will) change the CharSet based on the value being assigned, thus losing your manual assignment.Gare

© 2022 - 2024 — McMap. All rights reserved.