Delphi.cz

Český portál Delphi

System.Net.httpclient - THTTPClient z XE8

No minule jsem byl k THTTPClient trošku nespravedlivý, ve skutečnosti toho umí více než se zdálo. Kromě https bez nutnosti dodání OpenSSL pro různé platformy to má zajímavé možnosti ohledně paralelního zpracování. Ukáži na malém příkladu.

Ukáži nejprve příklad na zamyšlení a pak vysvětlím co to vlastně dělá.


implementation
uses
  System.Threading,
  System.Net.httpclient;

procedure TForm9.AllocateFile(const sUrl, sFile: string; var iSize: Integer);
var
  oClient: THTTPClient;
  oResponse: IHTTPResponse;
  oFile : TFileStream;
begin
  oClient := THTTPClient.Create;
  try
    if not oClient.CheckDownloadResume(sUrl) then
    begin
      ShowMessage('Not support resume, parallel demo abort, use Get method'); // download direct via oClient.Get
      Abort;
    end;
    oResponse := oClient.Head(sUrl);
    oFile := TFileStream.Create(sFile, fmCreate);
    try
      iSize := oResponse.ContentLength;
      oFile.Size := iSize;
    finally
      oFile.Free;
    end;
  finally
    oClient.Free;
  end;
end;

procedure TForm9.Button1Click(Sender: TObject);
var
  iSize: Integer;
const
  csUrl = 'http://vesta.informatik.rwth-aachen.de/ftp/pub/comp/Linux/knoppix/knoppix-cd/KNOPPIX_V7.2.0bootonly-2013-06-16-EN.iso';
  csFile = 'c:\temp\temp.iso';
  ciSlice = 10;
begin
  AllocateFile(csUrl, csFile, iSize);

  TParallel.&For(0, ciSlice - 1,
     procedure (iIndex: Integer)
     var
       iPartSize, iStart, iEnd: Int64;
       oClient: THTTPClient;
       oFile: TFileStream;
       LResponse: IHTTPResponse;
     begin
       // zjisti jaký blok mám vlastně stahovat
       iPartSize := iSize div ciSlice;
       iStart := iPartSize * iIndex;
       iEnd := iPartSize * (iIndex + 1);
       if iIndex = ciSlice - 1 then  // pro poslední blok malá korekce
         iEnd := iSize;

        oClient := THTTPClient.Create;
        try
          oFile := TFileStream.Create(csFile, fmOpenWrite or fmShareDenyNone);
          try
            oFile.Seek(iStart, soBeginning); // nastav se v souboru na místo
            LResponse := oClient.GetRange(csUrl, iStart, iEnd - 1, oFile); // get it!
          finally
            oFile.Free;
          end;
        finally
          oClient.Free;
        end;
     end
  );
  ShowMessage('Downloaded!');
end;

end.

Kromě THttpClient kód používá možností knihovny System.Threading z XE7: anonymní metodu pouštěnou 10x za pomocí TParallel.For (ten znak & není chyba, ale možnost jak napsat klíčové slovo). Každá instance anonymní metody stáhne svoji část dat do připraveného souboru a celek počká na dokončení všech úloh a pak zahlásí informaci o stažení.

Ano, mohl jsem použít TThread přímo, ale není to takto více čitelnější?

Pro upřesnění: metoda AllocateFile vytvoří na disku prázdný soubor o velikosti budoucího stahovaného souboru. Velikost se získá za pomoci volání THttpClient.Head, kdy se vrací informace o stahovatelných datech. Nejprve se ale zjistí, zda server vůbec podporuje Resume u HTTP (metoda CheckDownloadResume), pokud ne, tak se demo ukončí - na normálním stahování není nic zvláštního.

Samozřejmě si jako vždy rád přečtu Vaše názory v komentářích.

Update: Igor mi napsal o nějakém problému v XE8.1, opraveno v Delphi 10

V XE8 Update 1 je nějaká ptákovina, takže na některých Windows (třeba Windows Server 2008) se ztrácejí parametry u metody GET. Možná by bylo dobré přidat tam komentář, aby si někdo nenabil jako já. Přepsal jsem asi 20 unit, všechno šlapalo jak hodinky, pak to dám na server a konečná. Ztrávil jsem tím několik báječných hodin a na nic jsem nepřišel. Prostě to nechodí. Příslušný server hlásí, že nedostal některé parametry. U mě se to projevilo u GET ve spojení s HTTPS, ale našel jsem report v QC, kde to dalším lidem zlobí zřejmě i na HTTP. Dle toho reportu je tam nějaký bug zanesený v update 1, protože stejný kód jim v XE8 chodil.

quality.embarcadero.com/browse/RSP-11479

Datum: 2015-04-19 22:59:00 Tagy: XE8, Indy, synapse, RTL, paralel

Novinky v Delphi