线程内同一 IdHTTP 的多个请求
Multiple requests on same IdHTTP inside thread
我有一个每天发出数千个 HTTP 请求的应用程序。
为了获得最佳性能,我决定只创建一次 IdHTTP 对象并将该对象用于所有请求。
这是问题开始的地方。在为每个请求创建一个 IdHTTP 时,一切都很顺利。
代码非常基础:
constructor HTTPThread.Create;
begin
inherited Create(false);
httpObject:= TIdHTTP.Create(Nil);
sslObject:= TIdSSLIOHandlerSocketOpenSSL.Create(Nil);
sslObject.SSLOptions.Method:= sslvTLSv1_2;
httpObject.IOHandler:= sslObject;
httpObject.Request.Accept:= frmHTTPRequests.Edit1.Text;
httpObject.Request.UserAgent:= frmHTTPRequests.Edit3.Text;
httpObject.ReadTimeout:= 15000;
httpObject.HandleRedirects:= true;
FreeOnTerminate:= true;
OnTerminate:= TerminateProc;
end;
procedure HTTPThread.DoRequests;
var
htmlSource: string;
begin
try
htmlSource:= httpObject.Get(Link);
//a bunch of other stuff with HTML source
except
on E : Exception do
Synchronize(procedure
begin
errorList.Add(E.Message);
errorList.SaveToFile('Error.txt');
end);
end;
end;
除了保存 Error.txt 文件以观察发生了什么,我创建了这个...
代码有时对于前 1k 个请求运行良好,有时对于前 2k 个请求,它会有所不同。突然,它开始在 TXT 文件上写入相同的错误:
Connection reset by peer. domain.com - Socket Error # 10054
我尝试断开 httpObject,尝试 httpObject.Request.Clear,似乎没有任何效果。
有没有机会使这项工作?
由于某些原因,当服务器响应 Connection reset by peer
时,Indy 不会关闭套接字,因此您需要手动关闭套接字。
procedure HTTPThread.DoRequests;
const
MAX_TRIES_COUNT = 5;
var
htmlSource: string;
TriesCount: Integer;
begin
TriesCount := 0;
repeat
try
htmlSource:= httpObject.Get(Link);
//a bunch of other stuff with HTML source
except
on E: Exception do
begin
if E.Message.Contains('by peer') then
begin
httpObject.Disconnect;
// Try to solve network connection issues
Continue;
end
else
begin
// Some other error handlers
end;
end;
inc(TriesCount);
end;
until (httpObject.ResponseCode = 200) or (TriesCount > MAX_TRIES_COUNT);
end;
P.S。我不建议您使用 Synchronize()
进行线程同步。尝试改用 TCriticalSection or TMonitor。
我有一个每天发出数千个 HTTP 请求的应用程序。 为了获得最佳性能,我决定只创建一次 IdHTTP 对象并将该对象用于所有请求。 这是问题开始的地方。在为每个请求创建一个 IdHTTP 时,一切都很顺利。 代码非常基础:
constructor HTTPThread.Create;
begin
inherited Create(false);
httpObject:= TIdHTTP.Create(Nil);
sslObject:= TIdSSLIOHandlerSocketOpenSSL.Create(Nil);
sslObject.SSLOptions.Method:= sslvTLSv1_2;
httpObject.IOHandler:= sslObject;
httpObject.Request.Accept:= frmHTTPRequests.Edit1.Text;
httpObject.Request.UserAgent:= frmHTTPRequests.Edit3.Text;
httpObject.ReadTimeout:= 15000;
httpObject.HandleRedirects:= true;
FreeOnTerminate:= true;
OnTerminate:= TerminateProc;
end;
procedure HTTPThread.DoRequests;
var
htmlSource: string;
begin
try
htmlSource:= httpObject.Get(Link);
//a bunch of other stuff with HTML source
except
on E : Exception do
Synchronize(procedure
begin
errorList.Add(E.Message);
errorList.SaveToFile('Error.txt');
end);
end;
end;
除了保存 Error.txt 文件以观察发生了什么,我创建了这个... 代码有时对于前 1k 个请求运行良好,有时对于前 2k 个请求,它会有所不同。突然,它开始在 TXT 文件上写入相同的错误:
Connection reset by peer. domain.com - Socket Error # 10054
我尝试断开 httpObject,尝试 httpObject.Request.Clear,似乎没有任何效果。 有没有机会使这项工作?
由于某些原因,当服务器响应 Connection reset by peer
时,Indy 不会关闭套接字,因此您需要手动关闭套接字。
procedure HTTPThread.DoRequests;
const
MAX_TRIES_COUNT = 5;
var
htmlSource: string;
TriesCount: Integer;
begin
TriesCount := 0;
repeat
try
htmlSource:= httpObject.Get(Link);
//a bunch of other stuff with HTML source
except
on E: Exception do
begin
if E.Message.Contains('by peer') then
begin
httpObject.Disconnect;
// Try to solve network connection issues
Continue;
end
else
begin
// Some other error handlers
end;
end;
inc(TriesCount);
end;
until (httpObject.ResponseCode = 200) or (TriesCount > MAX_TRIES_COUNT);
end;
P.S。我不建议您使用 Synchronize()
进行线程同步。尝试改用 TCriticalSection or TMonitor。