【问题标题】:Getting HTML from response stream using Indy's IDTCPClient [closed]使用 Indy 的 IDTCPClient 从响应流中获取 HTML [关闭]
【发布时间】:2013-12-01 19:22:48
【问题描述】:

我有一个以前的员工创建的组件。它使用 Indy (IDTCPClient) 和以下方法来执行请求(其中“aReadHeader”是 在传入之前构建的预定义 Uri)。

function TMyConnector.GET(aRawHeader: String): String;
begin
if Not Connected then Connected := True;
if Connected then
  begin
  FRawRequest :=  'GET /'+ aRawHeader + ' HTTP/'+HTTPVerText+#13#10+
                  'Host: '+FHost+#13#10+

                  'Cookie: UserHPos=IOGLO00003000090000C000BS; '+
                  'LOSID=qsBiy/wEDCq6tOXFzGbOlTD1lmo5AXdFnCkbzzPn6+qCeheYVyTcumRrjsqh+Hds4Fr2gZDazfDzGN1RA+nnHuQQeBy78ZUgctrZyyy9MnGl2qI/ulkV6EPxAfmmLg/lopRq99f5gAcG/dgtytAJjS+aD5DqtHGrAqjiqgtkwuA=; '+
                  'LoginHPos=IOGLO00003000090000C000BS; '+
                  'UIHPos=IOGLO00003000020000500003; '+
                  'LOSG=61939308-7C83-47ED-B909-2D2D10AD7026; '+
                  'fControllingBusiness=IOGLO000030000900001000050000200001'+#13#10+

                  'Connection: Close'+#13#10+
                  #13#10;

  FSock.Socket.Write(FRawRequest);
  FRawResponse := FSock.Socket.ReadLn(#13#10#13#10,nil);
  Result := FRawResponse;
  if ResponseStream = nil then ResponseStream := TMemoryStream.Create
    else ResponseStream.SetSize(0);
  FSock.Socket.ReadStream(ResponseStream,-1,True);
  if Connected and (Not KeepAlive) then Connected := False;
  end;
end;

质疑 FRawResponse 返回的问题

HTTP/1.0 200 OK 内容长度:5560 日期:2013 年 11 月 18 日星期一 15:05:07 GMT 内容类型:text/html; charset=UTF-8 ...,public

我如何才能真正将这个 html 内容从 ResponseStream 获取到 HTML

目前存在的一种方法是“GenerateJSON”(参见下面的代码)。我想创建一个名为“GenerateHTML”

Function StreamToArray(Strm:TStream):TArray<Byte>;
Begin
 Strm.Position := 0;
 SetLength(Result,Strm.Size);
 Strm.Read(Result[0],Strm.Size);
End;


Procedure TMyConnector.GenerateJSON;
begin
 if ResponseStream <> nil then
  Begin
   ResponseJSON_V := TJSONObject.ParseJSONValue(StreamToArray(ResponseStream),0) as TJSONValue; // Note ResponseJSON_V is declared as TJSONValue in TMyConnector);
  End;
end;

所以,我需要

Procedure TMyConnector.GenerateHTML;
begin
 if ResponseStream <> nil then
  Begin
   // result:= html from stream here
  End;
end;

编辑:

Procedure TMyConnector.GenerateXML;
var
 S: String;
begin
if ResponseStream <> nil then
  Begin
   try
    while FSock.IOHandler.CheckForDataOnSource(30) do
    begin
       S := FSock.IOHandler.InputBufferAsString;
    end;
  finally
    ResponseStr_v:= S;
  end;
  End;
end;

【问题讨论】:

  • 请将您的两个问题分成两个不同的问题。
  • 您为什么不使用专为此而设计的TIdHTTP?否则,您似乎是在尝试重新发明轮子。
  • 我应该换一种说法——为什么这篇文章的原作者选择不使用为此设计的TIdHTTP?我知道这不是您的选择,但如果您进行此切换,也许您会发现这会容易得多。
  • 您在编辑中添加的代码的目的是什么?你想问另一个问题吗?
  • @LIVESTUFF:如果你要开始抨击别人,请去其他地方。我将您的评论标记为“粗鲁或冒犯”。

标签: delphi sockets indy delphi-xe5


【解决方案1】:

之前的员工显然不知道 Indy 的 TIdHTTP 组件的存在,也不知道 Indy 的 ReadStream() 方法实际上是如何工作的,或者 HTTP 是如何实际工作的。您应该重新编写函数以使用TIdHTTP 并让它为您处理所有细节,例如:

function TMyConnector.GET(aRawHeader: String): String;
begin
  FHTTP.ProtocolVersion := ...; // pv1_0 or pv1_1

  // Indy has a TIdCookieManager component that can be attached to
  // the TIdHTTP.CookieManager property, which handles parsing,
  // tracking, and sending back cookies for you for each HTTP
  // request, so this should be re-written to utilize that
  // functionality...
  //
  FHTTP.Request.CustomHeaders.Values['Cookie'] := 'UserHPos=IOGLO00003000090000C000BS; '+
  'LOSID=qsBiy/wEDCq6tOXFzGbOlTD1lmo5AXdFnCkbzzPn6+qCeheYVyTcumRrjsqh+Hds4Fr2gZDazfDzGN1RA+nnHuQQeBy78ZUgctrZyyy9MnGl2qI/ulkV6EPxAfmmLg/lopRq99f5gAcG/dgtytAJjS+aD5DqtHGrAqjiqgtkwuA=; '+
  'LoginHPos=IOGLO00003000090000C000BS; '+
  'UIHPos=IOGLO00003000020000500003; '+
  'LOSG=61939308-7C83-47ED-B909-2D2D10AD7026; '+
  'fControllingBusiness=IOGLO000030000900001000050000200001';

  FHTTP.Request.Connection := 'Close';

  if ResponseStream = nil then
    ResponseStream := TMemoryStream.Create
  else
    ResponseStream.Size := 0;

  try
    try
      FHTTP.Get('http://' + FHost + '/' + aRawHeader, ResponseStream);
    finally
      FRawResponse := FHTTP.Response.RawHeaders.Text;
      Result := FRawResponse;
    end;
  except
    on E: EIdHTTPProtocolException do
    begin
      // HTTP error response. You can grab the error content if you need it...
      WriteStringToStream(ResponseStream, E.ErrorMessage);
    end;
    on E: Exception do
    begin
      // some other error, handle as needed...
    end;
  end;
end;

如果无法重写以使用TIdHTTP,那么您必须更新原始代码以实际实现基本的 HTTP 解析。仅仅调用ReadStream() 是不够的,你必须知道WHEN 调用它,以及WHAT 参数传递给它。尝试更多类似的方法:

function TMyConnector.GET(aRawHeader: String): String;
var
  Headers: TIdHeaderList;
  Size: integer;

  function InternalReadLn: String;
  begin
    Result := FSock.IOHandler.ReadLn;
    if FSock.IOHandler.ReadLnTimedout then begin
      raise EIdReadTimeout.Create('');
    end;
  end;

  function ChunkSize: integer;
  var
    j: Integer;
    s: string;
  begin
    s := InternalReadLn;
    j := Pos(';', s); {do not localize}
    if j > 0 then begin
      s := Copy(s, 1, j - 1);
    end;
    Result := StrToInt('$' + Trim(s), 0);
  end;

begin
  if Not Connected then Connected := True;
  if Connected then
  begin
    FRawRequest :=  'GET /'+ aRawHeader + ' HTTP/'+HTTPVerText+#13#10+
                    'Host: '+FHost+#13#10+

                    'Cookie: UserHPos=IOGLO00003000090000C000BS; '+
                    'LOSID=qsBiy/wEDCq6tOXFzGbOlTD1lmo5AXdFnCkbzzPn6+qCeheYVyTcumRrjsqh+Hds4Fr2gZDazfDzGN1RA+nnHuQQeBy78ZUgctrZyyy9MnGl2qI/ulkV6EPxAfmmLg/lopRq99f5gAcG/dgtytAJjS+aD5DqtHGrAqjiqgtkwuA=; '+
                    'LoginHPos=IOGLO00003000090000C000BS; '+
                    'UIHPos=IOGLO00003000020000500003; '+
                    'LOSG=61939308-7C83-47ED-B909-2D2D10AD7026; '+
                    'fControllingBusiness=IOGLO000030000900001000050000200001'+#13#10+

                    'Connection: Close'+#13#10+
                    #13#10;

    FSock.IOHandler.Write(FRawRequest);
    FRawResponse := FSock.IOHandler.ReadLn(#13#10#13#10,nil);
    Result := FRawResponse;

    if ResponseStream = nil then ResponseStream := TMemoryStream.Create
    else ResponseStream.Size := 0;

    Headers := TIdHeaderList.Create(QuoteHTTP);
    try
      Headers.Text := FRawResponse;

      if Pos('chunked', LowerCase(Headers.Values['Transfer-Encoding']) > 0 then
      begin
        Size := ChunkSize;
        while Size <> 0 do begin
          FSock.IOHandler.ReadStream(ResponseStream, Size);
          InternalReadLn;
          Size := ChunkSize;
        end;
        repeat until InternalReadLn = '';
      end
      else if Headers.IndexOfName('Content-Length') <> -1 then
      begin
        FSock.IOHandler.ReadStream(ResponseStream, StrToInt64(Headers.Values['Content-Length']), False);
      end
      else
        FSock.IOHandler.ReadStream(ResponseStream, -1, True);
    finally
      Headers.Free;
    end;

    if Connected and (Not KeepAlive) then Connected := False;
  end;
end;

【讨论】:

    猜你喜欢
    • 2013-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-01
    • 2013-05-27
    • 2019-02-10
    相关资源
    最近更新 更多