Delphi TIdTcpServer 获取POST 浏览器发送的参数

Delphi TIdTcpServer get POST parameters sent by browser

我正在开发一个简单的 Web 服务器来与我在浏览器中运行的 Web 应用程序进行通信。

我成功地创建了一个IdTcpServer 并获得了浏览器提交的RequestHeaders。 我不知道如何获取表单的 POST 参数。

到目前为止,这是我的代码:

procedure TMyServer.WebServerExecute(AContext: TIdContext);
var
    RawData: String;
    TRequestHeader: TStringList;
begin
    TRequestHeader := TStringList.Create;

    // GET Request Headers
    RawData := AContext.Connection.Socket.ReadLn(IndyTextEncoding_UTF8);
    while RawData <> '' do
      begin
        TRequestHeader.Add(RawData);
        RawData := AContext.Connection.Socket.ReadLn(IndyTextEncoding_UTF8);
      end;

    // How To get POST or GET Parameters of the HTML form?
    // ...

    // Respond to the Client
    Respond(...);

    TRequestHeader.Free;
end;

收到请求 headers 后,您需要分析它们以了解消息 body 是否存在,以及它以何种格式编码以便您可以正确阅读(请参阅RFC 2616 section 4.4), 如:

procedure TMyServer.WebServerConnect(AContext: TIdContext);
begin
  AContext.Connection.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8;
end;

procedure TMyServer.WebServerExecute(AContext: TIdContext);
var
  ReqLine, Value: String;
  I: Integer;
  Size: Int64;
  TRequestHeader: TIdHeaderList;
begin
  TRequestHeader := TIdHeaderList.Create;
  try
    // GET Request Line ...
    ReqLine := AContext.Connection.IOHandler.ReadLn;

    // TODO: parse ReqLine as needed to extract HTTP version, resource, and query params ...

    // GET Request Headers ...
    repeat
      Value := AContext.Connection.IOHandler.ReadLn;
      if Value = '' then Break;
      TRequestHeader.Add(Value);
    until False;

    // alternatively:
    // AContext.Connection.IOHandler.Capture(TRequestHeader, '', False);

    // get POST or GET data ...

    Value := TRequestHeader.Values['Transfer-Encoding'];
    if (Value <> '') and (not TextIsSame(Value, 'identity')) then
    begin
      repeat
        Value := AContext.Connection.IOHandler.ReadLn;

        I := Pos(';', Value);
        if I > 0 then begin
          Value := Copy(Value, 1, I - 1);
        end;

        Size := StrToInt64('$' + Trim(S));
        if Size = 0 then begin
          Break;
        end;

        // read specified number of bytes as needed ...

        AContext.Connection.IOHandler.ReadLn; // read CRLF at end of chunk data
      until False;

      // read trailer headers
      repeat
        Value := AContext.Connection.IOHandler.ReadLn;
        if (Value = '') then Break;
        // update TRequestHeader as needed...
      until False;  
    end
    else
    begin
      Value := TRequestHeader.Values['Content-Length'];
      if Value = '' then
      begin
        // respond with 411 error
        Exit;
      end;

      Size := StrToInt64(Value);

      // read specified number of bytes as needed ...
    end;

    // process request as needed, based on the value of
    // ReqLine, TRequestHeader.Values['Content-Type'], etc ...

    // Respond to the Client
    Respond(...);
  finally
    TRequestHeader.Free;
  end;
end;

话虽这么说,Indy 有一个 TIdHTTPServer 组件可以为您处理实现 HTTP 协议的艰巨工作(这并不像您认为的那样微不足道)。你不应该为此使用 TIdTCPServer

您可以为 TIdHTTPServer.OnCommandGet 事件分配一个处理程序,并根据需要使用提供的 ARequestInfoAResponseInfo 参数。请求 headers 将在 ARequestInfo.RawHeaders 属性 和各种 sub-properties(ARequestInfo.ContentTypeARequestInfo.ContentLength 等)中。 GET/POST 数据将相应地位于 ARequestInfo.QueryParamsARequestInfo.FormParamsARequestInfo.PostStream 属性中,例如:

procedure TMyServer.WebServerCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
  // use ARequestInfo.RawHeaders and ARequestInfo.QueryParams as needed ...

  if ARequestInfo.CommandType = hcPOST then
  begin
    if IsHeaderMediaType(ARequestInfo.ContentType, 'application/x-www-form-urlencoded') then
    begin
      // use ARequestInfo.FormParams as needed ...
    end
    else begin
      // use ARequestInfo.PostStream as needed ...
    end;
  end else
  begin
    // process GET/HEAD requests as needed ...
  end;

  // Respond to the Client, by populating AResponseInfo as needed ...
end;