用 Delphi 捕获 HTML POST?

Capturing HTML POST with Delphi?

我想获得我在 HTML 和 Delphi 中发送的 post 值。我正在使用 TIdHTTPServer.

我的目标是获取POST发送的数据。但有一个问题。我把它作为 使用如下图所示的工具的“表单数据”。捕获 POST 请求。

不幸的是,当我发出与HTML相同的请求时,它没有看到POST .我该如何实现?

procedure TForm1.serviceCommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  receiveStream: TStream;
begin
  if ARequestInfo.URI = '/test.php' then
  begin
    if ARequestInfo.Command = 'POST' then
    begin
      receiveStream := ARequestInfo.PostStream;
      if Assigned(receiveStream) then
      begin
        LOG.Lines.Add(ReadStringFromStream(receiveStream));
      end;
      AResponseInfo.ResponseNo := 200;
    end;
  end;
end;

HTML POST请求(Delphi没有看到那个请求,我的目标是实现那个愿望。)

<form method="post" action="http://localhost:99/test.php"> 
    <input type="hidden" name="test" value="04545">
    <input type="submit" value="send"/>
</form>

首先,让我先说一下:

  • if ARequestInfo.Command = 'POST' then 应改为

    if TextIsSame(ARequestInfo.Command, 'POST') then

    或更好

    if ARequestInfo.CommandType = hcPOST then

  • OnCommand... 事件处理程序在工作线程的上下文中触发,因此对 UI 的任何访问都必须 同步与主要 UI 线程。

现在,您显示的 HTML 将 post 网络表单值发送到使用 application/x-www-webform-urlencoded 媒体类型的 HTTP 服务器。在 TIdHTTPServer.OnCommandGet 事件中,ARequestInfo.PostStream 属性 未与该媒体类型一起使用,而是 nil。 posted 网络表单值将以其原始 unparsed 格式在 ARequestInfo.FormParamsARequestInfo.UnparsedParams 属性中以及 parsed 格式 ARequestInfo.Params 属性 如果 TIdHTTPServer.ParseParams 属性 为 True(默认情况下)。

试试这个:

procedure TForm1.serviceCommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  testValue: string;
begin
  if ARequestInfo.URI <> '/test.php' then
  begin
    AResponseInfo.ResponseNo := 404;
    Exit;
  end;
  if ARequestInfo.CommandType <> hcPOST then
  begin
    AResponseInfo.ResponseNo := 405;
    Exit;
  end;
  testValue := ARequestInfo.Params.Values['test'];
  TThread.Queue(nil,
    procedure
    begin
      LOG.Lines.Add('test: ' + testValue);
    end
  );
  AResponseInfo.ResponseNo := 200;
end;

也就是说,您的测试工具中的“表单数据”是指 multipart/form-data 媒体类型。在 HTML 中,如果您想 post 您的网络表单使用该媒体类型,则必须在 <form> 元素的 enctype 参数中明确说明,例如:

<form method="post" action="http://localhost:99/test.php" enctype="multipart/form-data"> 
    <input type="hidden" name="test" value="04545">
    <input type="submit" value="send"/>
</form>

在这种情况下,TIdHTTPServer does not currently support parsing multipart/form-data posts,因此 ARequestInfo.PostStream 不会 nil,提供网络表单的原始字节,以便您可以根据需要手动解析数据。

您可以通过查看 ARequestInfo.ContentType 属性 来区分用于 post 网络表单的媒体类型,例如:

procedure TForm1.serviceCommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  testValue: string;
  data: string;
begin
  if ARequestInfo.URI <> '/test.php' then
  begin
    AResponseInfo.ResponseNo := 404;
    Exit;
  end;
  if ARequestInfo.CommandType <> hcPOST then
  begin
    AResponseInfo.ResponseNo := 405;
    Exit;
  end;
  if IsHeaderMediaType(ARequestInfo.ContentType, 'application/x-www-form-urlencoded') then
  begin
    testValue := ARequestInfo.Params.Values['test'];
    TThread.Queue(nil,
      procedure
      begin
        LOG.Lines.Add('test: ' + testValue);
      end
    );
    AResponseInfo.ResponseNo := 200;
  end
  else if IsHeaderMediaType(ARequestInfo.ContentType, 'multipart/form-data') then
  begin
    data := ReadStringFromStream(ARequestInfo.PostStream);
    TThread.Queue(nil,
      procedure
      begin
        LOG.Lines.Add('form-data: ' + data);
      end
    );
    AResponseInfo.ResponseNo := 200;
  end else
  begin
    AResponseInfo.ResponseNo := 415;
  end;
end;