0

我正在制作一个小型服务器类型的应用程序。

在网络浏览器中,我希望用户输入服务器地址并登录,然后我的服务器必须返回服务器上存在的文件的路径。该文件必须在用户的本地计算机上运行(这些是小的 Excel 文件,因此它可能会很快运行)。

有可能吗?我必须先下载文件然后运行它吗?

该文件应在登录后自动运行,因此我的服务器必须将文件发送到客户端计算机并在客户端计算机上运行。

你能给我看一个小例子吗?

PS 我使用 Indy 组件,但如果有人有更好的想法,我愿意接受建议。

4

1 回答 1

2

您所要求的在 HTTP 中在技术上是可行的,因为对任何 HTTP 请求的响应都可以是实际的 Excel 文件。例如:

使用 HTTP 身份验证:

procedure TMyForm.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
  if ARequestInfo.Document = '/myfile.xlsx' then
  begin
    if not ARequestInfo.AuthExists then
    begin
      AResponseInfo.AuthRealm := 'myserver';
      Exit;
    end;
    if not UserIsAuthenticated(ARequestInfo.AuthUsername, ARequestInfo.AuthPassword) then
    begin
      AResponseInfo.ResponseNo := 403;
      Exit;
    end;
    case ARequestInfo.CommandType of
      hcGET:
      begin
        AResponseInfo.SmartServeFile(AContext, ARequestInfo, '<path>\myfile.xlsx');
      end;
      hcHEAD:
      begin
        AResponseInfo.ContentType := IdHTTPServer1.MIMETable.GetFileMIMEType('myfile.xlsx');
        AResponseInfo.ContentLength := FileSizeByName('<path>\myfile.xlsx');
        AResponseInfo.ContentDisposition := 'attachment; filename="myfile.xlsx";';
      end;
    else
      AResponseInfo.ResponseNo := 405;
    end;
  end else
  begin
    AResponseInfo.ResponseNo := 404;
  end;
end;

使用 HTML 网络表单身份验证:

索引.html

<html>
<head>
<title>login</title>
</head>
<body>
<form action="/login" method="POST">
Username: <input type="text" name="user"><br>
Password: <input type="password" name="pswd"><br>
<input type="submit" value="Submit"> <input type="reset" value="Clear">
</form>
</body>
</html>
procedure TMyForm.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
  if ARequestInfo.Document = '/' then
  begin
    case ARequestInfo.CommandType of
      hcGET, hcHEAD:
      begin
        AResponseInfo.ContentType := 'text/html';
        if ARequestInfo.CommandType = hcGET then
          AResponseInfo.ContentStream := TIdReadFileExclusiveStream.Create('<path>\index.html')
        else
          AResponseInfo.ContentLength := FileSizeByName('<path>\index.html');
      end;
    else
      AResponseInfo.ResponseNo := 405;
    end;
  end
  else if ARequestInfo.Document = '/login' then
  begin
    if ARequestInfo.CommandType <> hcPOST then
    begin
      AResponseInfo.ResponseNo := 405;
      Exit;
    end;
    if not UserIsAuthenticated(ARequestInfo.Params.Values['user'], ARequestInfo.Params.Values['pswd']) then
    begin
      AResponseInfo.ResponseNo := 403;
      Exit;
    end;
    AResponseInfo.ServeFile(AContext, '<path>\myfile.xlsx');
  end else
  begin
    AResponseInfo.ResponseNo := 404;
  end;
end;

或者:

// make sure to set TIdHTTPServer.SessionState=True...

procedure TMyForm.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
  if ARequestInfo.Document = '/' then
  begin
    case ARequestInfo.CommandType of
      hcGET, hcHEAD:
      begin
        AResponseInfo.ContentType := 'text/html';
        if ARequestInfo.CommandType = hcGET then
          AResponseInfo.ContentStream := TIdReadFileExclusiveStream.Create('<path>\index.html')
        else
          AResponseInfo.ContentLength := FileSizeByName('<path>\index.html');
      end;
    else
      AResponseInfo.ResponseNo := 405;
    end;
  end
  else if ARequestInfo.Document = '/login' then
  begin
    if ARequestInfo.CommandType <> hcPOST then
    begin
      AResponseInfo.ResponseNo := 405;
      Exit;
    end;
    if ARequestInfo.Session = nil then
    begin
      IdHTTPServer1.CreateSession(AContext, AResponseInfo, ARequestInfo);
    end;
    if not UserIsAuthenticated(ARequestInfo.Params.Values['user'], ARequestInfo.Params.Values['pswd']) then
    begin
      AResponseInfo.Session.Content.Values['AuthOK'] := 'no';
      AResponseInfo.ResponseNo := 403;
      Exit;
    end;
    AResponseInfo.Session.Content.Values['AuthOK'] := 'yes';
    //AResponseInfo.Redirect('/myfile.xlsx');
    AResponseInfo.ResponseNo := 303;
    AResponseInfo.Location := '/myfile.xlsx';
  end
  else if ARequestInfo.Document = '/myfile.xlsx' then
  begin
    if ARequestInfo.AuthExists then
    begin
      if ARequestInfo.Session = nil then
      begin
        IdHTTPServer1.CreateSession(AContext, AResponseInfo, ARequestInfo);
      end;
      ARequestInfo.Session.Content.Values['AuthOK'] := iif(UserIsAuthenticated(ARequestInfo.AuthUsername, ARequestInfo.AuthPassword), 'yes', 'no');
    end;
    if (ARequestInfo.Session = nil) or (ARequestInfo.Session.Content.IndexOf('AuthOK') = -1) then
    begin
      //AResponseInfo.Redirect('/');
      AResponseInfo.ResponseNo := 303;
      AResponseInfo.Location := '/';
      Exit;
    end;
    if ARequestInfo.Session.Content.Values['AuthOK'] <> 'yes' then
    begin
      AResponseInfo.ResponseNo := 403;
      Exit;
    end;
    case ARequestInfo.CommandType of
      hcGET:
      begin
        AResponseInfo.SmartServeFile(AContext, ARequestInfo, '<path>\myfile.xlsx');
      end;
      hcHEAD:
      begin
        AResponseInfo.ContentType := IdHTTPServer1.MIMETable.GetFileMIMEType('myfile.xlsx');
        AResponseInfo.ContentLength := FileSizeByName('<path>\myfile.xlsx');
        AResponseInfo.ContentDisposition := 'attachment; filename="myfile.xlsx";';
      end;
    else
      AResponseInfo.ResponseNo := 405;
    end;
  end else
  begin
    AResponseInfo.ResponseNo := 404;
  end;
end;

然而,无论哪种方式,用户的网络浏览器都必须预先配置为.xlsx在 Excel(或他们想要的任何查看器/编辑器)中自动打开文件,或者至少提示用户是否打开文件。服务器不能强制文件自动打开,这会破坏用户的安全。

于 2018-04-27T17:07:22.143 回答