Delphi IdHTTP服务器加载html

标签 delphi indy

我已经创建了一个 VCL 应用程序,并且需要创建一个在我的网络中运行的 HTTP 服务器。我创建了您可以在下面看到的代码:

procedure TForm1.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  a: TStringList;
  count, logN: integer;
begin

 if ARequestInfo.Document = '/' then
  begin

   AResponseInfo.ResponseNo := 200;
   AResponseInfo.ContentText := IndexMemo.Lines.Text;
   Memo1.Lines.Add(' Client: ' + ARequestInfo.RemoteIP);

  end
 else
  begin

   AResponseInfo.ResponseNo := 200;
   AResponseInfo.ContentText := '<html><body><b>404 NOT FOUND</b></body></html>';

  end;

end;

现在我只有一个测试用例 if ARequestInfo.Document = '/' then 但稍后我将需要很多测试用例。我找到了这个解决方案:

  1. 在表单中添加备注
  2. 在备忘录中添加 html
  3. ContextText 中加载备忘录文本

我认为这不是非常有效,因为我必须在表单中删除大约 20 个 TMemo,并且 HTML 将很难维护。我认为我可以使用部署管理器加载html页面。

enter image description here

在 Delphi 项目的同一文件夹中,我创建了一个名为 pages 的文件夹,它将包含 html 文件。我不确定如何使用 indy HTTP 服务器加载 html 页面,所以我的问题是:

  1. 我是否必须将 html 页面存储在文件夹中的某个位置,然后使用 indy 加载它们?
  2. 我可以使用 indy 加载部署页面中包含的 html 页面吗?
<小时/>

注意:我想要一个 exe(即 http 服务器),而不是包含 exe + html 文件的文件夹。我发现的解决方案效果很好,因为我使用了很多 TMemo 来存储代码,但这并不容易维护。

最佳答案

首先,您显示的代码不是线程安全的。 TIdHTTPServer 是一个多线程组件,OnCommand... 事件在工作线程上下文中触发。您必须与主 UI 线程同步才能安全地访问 UI 控件,例如:

procedure TForm1.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  s: string;
begin
  if ARequestInfo.Document = '/' then
  begin
    TThread.Synchronize(nil,
      procedure
      begin
        s := IndexMemo.Lines.Text;
        Memo1.Lines.Add(' Client: ' + ARequestInfo.RemoteIP);
      end
    );

    AResponseInfo.ResponseNo := 200;
    AResponseInfo.ContentText := s;
    AResponseInfo.ContentType := 'text/plain';
  end
  else
  begin    
    AResponseInfo.ResponseNo := 404;
    AResponseInfo.ContentText := '<html><body><b>404 NOT FOUND</b></body></html>';
    AResponseInfo.ContentType := 'text/html';
  end;
end;
  1. Do I have to store the html pages somewhere in a folder and then load them using indy?

  2. Can I load html pages with indy that are included in the Deployment page?

如果您想从本地文件系统提供文件,则必须将 ARequestInfo.Document 属性值转换为本地文件路径,然后您可以:

  1. 将请求的文件加载到 TFileStream 中并将其分配给 AResponseInfo.ContentStream 属性:

    procedure TForm1.IdHTTPServer1CommandGet(AContext: TIdContext;
      ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
    var
      str, filename: string;
    begin
      str := ' Client: ' + ARequestInfo.RemoteIP + ' requesting: ' + ARequestInfo.Document;
      TThread.Queue(nil,
        procedure
        begin
          Memo1.Lines.Add(str);
        end
      );
    
      if TextStartsWith(ARequestInfo.Document, '/') then
      begin
        filename := Copy(ARequestInfo.Document, 2, MaxInt);
        if filename = '' then
          filename := 'index.txt';
    
        // determine local path to requested file
        // (ProcessPath() is declared in the IdGlobalProtocols unit)...
        filename := ProcessPath(YourDeploymentFolder, filename);
    
        if FileExists(filename) then
        begin
          AResponseInfo.ResponseNo := 200;
          AResponseInfo.ContentStream := TFileStream.Create(filename, fmOpenRead or fmShareDenyWrite);
          AResponseInfo.ContentType := IdHTTPServer1.MIMETable.GetFileMIMEType(filename);
          Exit;
        end;
      end;
    
      AResponseInfo.ResponseNo := 404;
      AResponseInfo.ContentText := '<html><body><b>404 NOT FOUND</b></body></html>';
      AResponseInfo.ContentType := 'text/html';
    end;
    
  2. 将文件路径传递给 TIdHTTPResponseInfo.(Smart)ServeFile() 方法并让它为您处理文件:

    procedure TForm1.IdHTTPServer1CommandGet(AContext: TIdContext;
      ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
    var
      str, filename: string;
    begin
      str := ' Client: ' + ARequestInfo.RemoteIP + ' requesting: ' + ARequestInfo.Document;
      TThread.Queue(nil,
        procedure
        begin
          Memo1.Lines.Add(str);
        end
      );
    
      if TextStartsWith(ARequestInfo.Document, '/') then
      begin
        filename := Copy(ARequestInfo.Document, 2, MaxInt);
        if filename = '' then
          filename := 'index.txt';
    
        // determine local path to requested file...
        filename := ProcessPath(YourDeploymentFolder, filename);
    
        AResponseInfo.SmartServeFile(AContext, ARequestInfo, filename);
        Exit;
      end;
    
      AResponseInfo.ResponseNo := 404;
      AResponseInfo.ContentText := '<html><body><b>404 NOT FOUND</b></body></html>';
      AResponseInfo.ContentType := 'text/html';
    end;
    

I would like to have a single exe (which is the http server) and not a folder with exe + html files.

在这种情况下,请在编译时将 HTML 文件保存到 EXE 的资源中(使用 .rc 文件或 IDE 的 Resources and Images 对话框。有关更多详细信息,请参阅 Resource Files Support)并然后将 ARequestInfo.Document 转换为资源 ID/名称,您可以使用 TResourceStream 加载该资源 ID/名称,以用作 AResponseInfo.ContentStream 对象:

procedure TForm1.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  str, resID: string;
  strm: TResourceStream;
begin
  str := ' Client: ' + ARequestInfo.RemoteIP + ' requesting: ' + ARequestInfo.Document;
  TThread.Queue(nil,
    procedure
    begin
      Memo1.Lines.Add(str);
    end
  );

  if TextStartsWith(ARequestInfo.Document, '/') then
  begin
    // determine resource ID for requested file
    // (you have to write this yourself)...
    resID := TranslateIntoResourceID(Copy(ARequestInfo.Document, 2, MaxInt));
    try
      strm := TResourceStream.Create(HInstance, resID, RT_RCDATA);
    except
      on E: EResNotFound do
        strm := nil;
    end;

    if strm <> nil then
    begin
      AResponseInfo.ResponseNo := 200;
      AResponseInfo.ContentStream := strm;
      AResponseInfo.ContentType := 'text/html';
      Exit;
    end;
  end;

  AResponseInfo.ResponseNo := 404;
  AResponseInfo.ContentText := '<html><body><b>404 NOT FOUND</b></body></html>';
  AResponseInfo.ContentType := 'text/html';
end;

关于Delphi IdHTTP服务器加载html,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43760241/

相关文章:

delphi - 单个 TIdHTTPServer 组件可以同时处理 http 和 https 请求吗?

delphi - 通过 Delphi 和 Indy 10 TIdHTTP 获取 WebDAV 内容

Delphi VCL for Win32 - 多个事件处理程序

delphi - 表单关闭时 Acrobat Reader ActiveX 访问冲突

delphi - TidHTTP 错误处理

delphi - Indy IMAP 在点处切断消息

delphi - Indy http 后解码

delphi - Windows 7 中的 Delphi 代码存储在哪里?

delphi - 如何卸载JVCL?

delphi - 解决 Delphi 中整数溢出的最佳方法是什么?