Delphi

Download e upload con avanzamento: estendere TIdHTTP in Delphi

calendar_today personTeam EGSOFT schedule4 min di lettura
info

Disclaimer: le informazioni pubblicate in questa sezione hanno finalità di pura divulgazione tecnica. EG Software S.r.l. non si assume alcuna responsabilità per un utilizzo improprio dei contenuti, né per eventuali danni diretti o indiretti derivanti dalla loro applicazione, e non garantisce l'aggiornamento, l'accuratezza o la completezza delle informazioni riportate. Prima di utilizzare in produzione codice o procedure qui descritte, verificane sempre l'adeguatezza al proprio contesto.

Quando un'applicazione Delphi deve scaricare o caricare file da un server, il componente TIdHTTP della libreria Indy è quasi sempre la scelta più diretta: fa parte della distribuzione standard di Delphi e gestisce da solo buona parte delle complessità del protocollo HTTP. Il problema arriva quando serve mostrare all'utente l'avanzamento dell'operazione: la soluzione più pulita è creare una classe discendente che intercetta gli eventi di progresso di Indy.

Estendere TIdHTTP con una property ProgressBar

L'idea di base è semplice: incapsulare un TProgressBar dentro una classe che eredita da TIdHTTP, e aggiornarlo automaticamente durante il trasferimento.

unit HttpConAvanzamento;

interface

uses
  System.Classes, IdHTTP, IdComponent, Vcl.ComCtrls;

type
  TCustomHTTP = class(TIdHTTP)
  private
    FProgressBar: TProgressBar;
    procedure GestisciAvanzamento(ASender: TObject;
      const ABytesTransferred, AContentLength: Int64);
  public
    constructor Create(AOwner: TComponent; AProgressBar: TProgressBar); reintroduce;
    property ProgressBar: TProgressBar read FProgressBar write FProgressBar;
  end;

implementation

constructor TCustomHTTP.Create(AOwner: TComponent; AProgressBar: TProgressBar);
begin
  inherited Create(AOwner);
  FProgressBar := AProgressBar;
end;

procedure TCustomHTTP.GestisciAvanzamento(ASender: TObject;
  const ABytesTransferred, AContentLength: Int64);
begin
  if Assigned(FProgressBar) then
  begin
    FProgressBar.Max := AContentLength;
    FProgressBar.Position := ABytesTransferred;
  end;
end;

end.

L'evento da cui arrivano queste informazioni è OnWork (in alcune versioni affiancato da OnWorkBegin e OnWorkEnd, utili per resettare la barra a inizio e fine operazione): Indy lo invoca periodicamente durante la lettura o scrittura dello stream, passando i byte trasferiti e — quando il server la dichiara nell'header — la dimensione totale del contenuto.

Aggiungere l'upload con IdMultipartFormData

La stessa classe può gestire anche l'upload, tipicamente in multipart/form-data, distinguendo l'evento di progresso per le due direzioni tramite due handler separati assegnati prima di ogni operazione:

procedure TCustomHTTP.ScaricaFile(const URL, NomeFile: string);
begin
  OnWork := GestisciAvanzamentoDownload;
  Get(URL, NomeFile);
end;

procedure TCustomHTTP.CaricaFile(const URL, NomeFile: string);
var
  DatiForm: TIdMultipartFormDataStream;
begin
  OnWork := GestisciAvanzamentoUpload;
  DatiForm := TIdMultipartFormDataStream.Create;
  try
    DatiForm.AddFile('file', NomeFile, '');
    Post(URL, DatiForm);
  finally
    DatiForm.Free;
  end;
end;

Nell'uso reale conviene anche avvolgere le chiamate a Get e Post in un blocco try..except che intercetti EIdHTTPProtocolException (per gli errori HTTP restituiti dal server, come 404 o 500) ed EIdSocketError (per problemi di rete o timeout), così l'interfaccia può mostrare un messaggio comprensibile invece di lasciar propagare l'eccezione grezza di Indy.

Un dettaglio che conviene non dimenticare

Se TCustomHTTP viene usato dentro un TThread secondario, ricorda che l'aggiornamento della TProgressBar deve comunque avvenire nel thread principale: va incapsulato in una TThread.Queue o TThread.Synchronize, altrimenti si rischiano errori intermittenti e difficili da riprodurre sull'interfaccia grafica.

Con questa struttura hai una classe HTTP riutilizzabile in tutta l'applicazione, che si comporta come TIdHTTP ma con il feedback visivo integrato — utile per form di importazione dati, aggiornamento automatico o sincronizzazione con servizi esterni.

Altri articoli su Delphi grid_viewTutte le tematiche
Scrivici su WhatsApp