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.