Problemas de TNetHttpClient en entornos multihilo en Delphi 10.3.1 y soluciones alternativas

Delphi 10.3.1 ha sido lanzado con numerosas correcciones para problemas existentes en la versión 10.3.0. Sin embargo, se ha identificado un problema con TNetHttpClient cuando se utiliza en entornos multihilo, específicamente en plataformas Android. A continuación se detalla el problema y su solución.

El siguiente código demuestra el problema al crear múltiples instancias de TNetHttpClient en hilos separados:

procedure TForm1.PruebaConcurrenciaClick(Sender: TObject);
var
  i: Integer;
begin
  for i := 1 to 3 do // Más de 2 hilos causan problemas
  begin
    TThread.CreateAnonymousThread(
      procedure()
      var
        clienteWeb: TNethttpClient;
        respuestaContenido: Tstream;
        contador: Integer;
        tamanoContenido: Integer;
        idHilo:Cardinal;
      begin
        contador := 0;
        idHilo:=TThread.Current.ThreadID;
        clienteWeb := TNethttpClient.Create(Self);
        try
          while true do
          begin
            Inc(contador);
            respuestaContenido := TMemoryStream.Create;
            try
              clienteWeb.Accept := 'text/javascript, text/html, application/xml, text/xml, /';
              clienteWeb.AcceptLanguage := 'en-US,en;q=0.8,fr;q=0.6';
              clienteWeb.UserAgent := 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36';
              try
                clienteWeb.Get('https://www.cnblogs.com/kinglandsoft/p/10383103.html', respuestaContenido);
              except
                On E: Exception do
                begin
                  TThread.Synchronize(nil,
                    procedure()
                    begin
                      if Memo1.Lines.Count > 500 then
                        Memo1.Lines.Clear;
                      Memo1.Lines.Add('Error: ' + E.Message);
                    end);
                end;
              end;
              tamanoContenido := respuestaContenido.Size;

              TThread.Synchronize(nil,
                procedure()
                var
                  mensaje: string;
                begin
                  mensaje := Format('Intento=%d, Tamaño:%d en hilo id:%s',
                    [contador, tamanoContenido, idHilo.ToString]);
                  Etiqueta1.Text := mensaje;
                  Memo1.Lines.Add(mensaje);
                  if Memo1.Lines.Count > 500 then
                    Memo1.Lines.Clear;
                end);
            finally
              respuestaContenido.Free;
            end;
          end;
        finally
          clienteWeb.Free;
        end;
      end).Start;
  end;
end;

Este código crea múltiples hilos que utilizan instancias de TNetHttpClient para acceder al mismo recurso. Se observa que con 2 o menos hilos el funcionamiento es correcot, pero al superar este número aparecen problemas en la plataforma Android, mientras que en Win32 el comportamiento es normal.

Se ha reportado este problema a Embarcadero en https://quality.embarcadero.com/browse/RSP-23742. Si te encuentras con este inconveniente, te recomendamos votar el reporte para presionar por una corrección oficial.

Mientras se soluciona oficialmente, puedes utilizar idHTTP como alternativa temporal.

Solución temporal:

Una solución efectiva es copiar la unidad System.Net.HttpClient.pas a tu carpeta de proyecto y modificar la estructura THTTPClientExt de la siguiente manera:

  THTTPClientExt = record
    case Integer of
    0: (
      FPreemptiveAuthentication: Boolean;
      FSecureFailureReasons: THTTPSecureFailureReasons;
      FAutomaticDecompression: THTTPCompressionMethods
    );
    1: (
      _relleno: array[0 .. 7] of Byte
    );
  end;

Este cambio ha demostrado resolver el problema en las pruebas realizadas. Es importante recordar que si no copias la unidad al directorio del proyecto, debes añadir la carpeta donde se encuentra System.Net.HttpClient.pas al Search Path de tu proyecto.

Etiquetas: Delphi TNetHttpClient Multithreading Android Embarcadero

Publicado el 6-15 22:55