Delphi IdHTTP 服务器负载 html
Delphi IdHTTP server load html
我已经创建了一个 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
但以后我会需要很多。我找到了这个解决方案:
- 在表单中添加备忘录
- 在备忘录中添加html
- 在
ContextText
中加载备忘录的文本
我认为这不是很有效,因为我必须在我的表单中删除 20 个 TMemo 并且 HTML 将难以维护。我以为我可以用 Deployment manager
.
加载 html 页面
在 Delphi 项目的同一文件夹中,我创建了一个名为 pages
的文件夹,它将包含 html 文件。我不确定如何使用独立 HTTP 服务器加载 html 页面,所以我的问题是:
- 我是否必须将 html 页面存储在某个文件夹中,然后使用 indy 加载它们?
- 我可以加载包含在部署页面中的 html 页面吗?
注意:我想要一个单独的 exe(它是 http 服务器)而不是包含 exe + html 文件的文件夹。我找到的解决方案效果很好,因为我使用了很多 TMemo
来存储代码,但这并不容易维护。
您可以从文件中读取内容
procedure TForm2.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var Page : TStringStream;
begin
Page := TStringStream.Create;
Page.LoadFromFile('put the file path here');
AResponseInfo.ResponseNo := 200;
AResponseInfo.ContentStream := page;
end;
您可以从资源中读取内容,转到项目菜单、资源和图像,添加您需要的资源。
procedure TForm2.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var page : TResourceStream;
begin
//home is the resource name
page := TResourceStream.Create(HInstance, 'home', RT_RCDATA);
AResponseInfo.ResponseNo := 200;
AResponseInfo.ContentStream := page;
end;
首先,您显示的代码不是线程安全的。 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;
Do I have to store the html pages somewhere in a folder and then load them using indy?
Can I load html pages with indy that are included in the Deployment page?
如果您想从本地文件系统提供文件,您必须将 ARequestInfo.Document
属性 值转换为本地文件路径,然后您可以:
将请求的文件加载到 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;
将文件路径传递给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 dialog. See Resource Files Support更多详细信息),然后将 ARequestInfo.Document
转换为资源 ID/Name,您可以使用 TResourceStream
加载该资源以用作 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;
我已经创建了一个 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
但以后我会需要很多。我找到了这个解决方案:
- 在表单中添加备忘录
- 在备忘录中添加html
- 在
ContextText
中加载备忘录的文本
我认为这不是很有效,因为我必须在我的表单中删除 20 个 TMemo 并且 HTML 将难以维护。我以为我可以用 Deployment manager
.
在 Delphi 项目的同一文件夹中,我创建了一个名为 pages
的文件夹,它将包含 html 文件。我不确定如何使用独立 HTTP 服务器加载 html 页面,所以我的问题是:
- 我是否必须将 html 页面存储在某个文件夹中,然后使用 indy 加载它们?
- 我可以加载包含在部署页面中的 html 页面吗?
注意:我想要一个单独的 exe(它是 http 服务器)而不是包含 exe + html 文件的文件夹。我找到的解决方案效果很好,因为我使用了很多 TMemo
来存储代码,但这并不容易维护。
您可以从文件中读取内容
procedure TForm2.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var Page : TStringStream;
begin
Page := TStringStream.Create;
Page.LoadFromFile('put the file path here');
AResponseInfo.ResponseNo := 200;
AResponseInfo.ContentStream := page;
end;
您可以从资源中读取内容,转到项目菜单、资源和图像,添加您需要的资源。
procedure TForm2.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var page : TResourceStream;
begin
//home is the resource name
page := TResourceStream.Create(HInstance, 'home', RT_RCDATA);
AResponseInfo.ResponseNo := 200;
AResponseInfo.ContentStream := page;
end;
首先,您显示的代码不是线程安全的。 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;
Do I have to store the html pages somewhere in a folder and then load them using indy?
Can I load html pages with indy that are included in the Deployment page?
如果您想从本地文件系统提供文件,您必须将 ARequestInfo.Document
属性 值转换为本地文件路径,然后您可以:
将请求的文件加载到
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;
将文件路径传递给
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 dialog. See Resource Files Support更多详细信息),然后将 ARequestInfo.Document
转换为资源 ID/Name,您可以使用 TResourceStream
加载该资源以用作 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;