【问题标题】:Delphi TIdTcpServer get POST parameters sent by browserDelphi TIdTcpServer 获取浏览器发送的 POST 参数
【发布时间】:2019-09-17 19:23:03
【问题描述】:

我正在开发一个简单的 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;

【问题讨论】:

  • 整个(简单)HTTP 请求是一个单一的“文本”文档。标题和内容部分仅用空行分隔。最后,您应该在 TStringList 中拥有整个请求,而不仅仅是标头。我不确定 Indy 组件是如何工作的,但可能会发生您需要继续读取套接字直到它结束的情况。然后你应该解析你得到的东西。有相当多的 RFC 描述了 HTTP 请求,但您也可以在网络上找到简单的示例。
  • 但是,除非你想学习这部分,否则你不应该走这条路。为此类测试目的启动 python 或节点网络服务器比实现自己的要容易得多。
  • Indy 有一个 TIdHTTPServer(和一个 TIdCustomHTTPServer)。如果您要走这条路,我强烈建议您使用最适合该任务的对象。 Web 通信是通过 HTTP(S) 完成的,而不是普通的 TCP/IP。

标签: delphi indy tcpserver


【解决方案1】:

获得请求标头后,您需要对其进行分析以了解消息正文是否存在,以及以何种格式对其进行编码,以便您可以正确阅读它(请参阅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 参数。请求标头将位于ARequestInfo.RawHeaders 属性和各种子属性(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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-05
    • 2012-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-30
    • 1970-01-01
    • 2018-02-18
    相关资源
    最近更新 更多