Reputation: 53
How to use asynchronous TNetHTTPClient? I tried following code, but it shows error.
procedure TForm1.Button1Click(Sender: TObject);
var
httpclient: TNetHTTPClient;
output: string;
begin
httpclient := TNetHTTPClient.Create(nil);
try
httpclient.Asynchronous := True;
output := httpclient.Get('https://google.com').ContentAsString;
finally
httpclient.Free;
end;
end;
Error:
Error querying headers: The handle is in a wrong state for the requested operation
Upvotes: 1
Views: 2517
Reputation: 1
Here you have two versions - one for GET and one for POST (with response). Beware of Modsecurity issues on the server you want to use it on and other server settings which may cause the code not to work as expected (as happened to me when my POST was processed as GET by the server).
For POST, I am using Params.Add('input=' + TNetEncoding.URL.Encode(AText)); you can also use text= instead of input= and I store the response in URLMemo, which you can change to whatever you need.
procedure TUExtractForm.LoadURLAsync(const AURL: string);
const
CONST_TIMEOUT = 30000;
begin
TTask.Run(
procedure
var
HttpClient: TNetHTTPClient;
HTTPRequest: TNetHTTPRequest;
begin
try
HttpClient := TNetHTTPClient.Create(nil);
try
HttpClient.ConnectionTimeout := CONST_TIMEOUT; // Timeout
HttpClient.ResponseTimeout := CONST_TIMEOUT; // Timeout
HTTPRequest := TNetHTTPRequest.Create(HttpClient);
HTTPRequest.Client := HttpClient;
HTTPRequest.OnRequestCompleted := HTTPRequestCompleted;
HTTPRequest.OnRequestError := HTTPRequestError;
HTTPRequest.Get(AURL);
finally
HttpClient.Free;
end;
except
on E: Exception do
begin
TThread.Queue(nil,
procedure
begin
ShowMessageFmt('Error: %s', [E.Message]);
end);
end;
end;
end);
end;
procedure TUExtractForm.LoadURLAsyncPOST(const AURL, AText: string);
const
CONST_TIMEOUT = 30000;
begin
TTask.Run(
procedure
var
HttpClient: TNetHTTPClient;
HTTPRequest: TNetHTTPRequest;
ParamsStream: TBytesStream;
begin
ParamsStream := nil;
try
HttpClient := TNetHTTPClient.Create(nil);
try
HttpClient.ConnectionTimeout := CONST_TIMEOUT; // Timeout
HttpClient.ResponseTimeout := CONST_TIMEOUT; // Timeout
HTTPRequest := TNetHTTPRequest.Create(HttpClient);
HTTPRequest.Client := HttpClient;
HTTPRequest.OnRequestCompleted := HTTPRequestCompleted;
HTTPRequest.OnRequestError := HTTPRequestError;
HTTPRequest.CustomHeaders['Content-Type'] := 'application/x-www-form-urlencoded';
ParamsStream := TBytesStream.Create(TEncoding.UTF8.GetBytes('input=' + TNetEncoding.URL.Encode(AText)));
HTTPRequest.Post(AURL, ParamsStream);
finally
HttpClient.Free;
ParamsStream.Free;
end;
except
on E: Exception do
begin
TThread.Queue(nil,
procedure
begin
ShowMessageFmt('Error: %s', [E.Message]);
end);
end;
end;
end);
end;
procedure TUExtractForm.HTTPRequestCompleted(const Sender: TObject; const AResponse: IHTTPResponse);
var
Content: string;
begin
if AResponse.StatusCode = 200 then
begin
Content := AResponse.ContentAsString;
// replace #$A with new line
Content := StringReplace(Content, #$A, sLineBreak, [rfReplaceAll]);
URLMemo.Text := Content;
end;
end;
procedure TUExtractForm.HTTPRequestError(const Sender: TObject; const AError: string);
begin
ShowMessageFmt('Error: %s', [AError]);
end;
Upvotes: 0
Reputation: 28519
In asynchronous mode, as the name implies, client runs request asynchronously in the background thread.
When following code is executed, ContentAsString
fails because request is not completed at that point.
output := httpclient.Get('https://google.com').ContentAsString
If you want to use HTTP client in asynchronous mode, you will have to use completion handlers to run appropriate code after request is completed.
procedure TForm1.Button1Click(Sender: TObject);
var
httpclient: TNetHTTPClient;
begin
httpclient := TNetHTTPClient.Create(nil);
httpclient.Asynchronous := True;
httpclient.OnRequestCompleted := HTTPRequestCompleted;
httpclient.Get('https://google.com');
end;
procedure TForm1.HTTPRequestCompleted(const Sender: TObject; const AResponse: IHTTPResponse);
var
output: string;
begin
output := AResponse.ContentAsString;
Sender.Free;
end;
Using HTTP client in asynchronous mode is generally more complicated (especially from the memory management aspect) than using it in synchronous mode from the background thread.
Following is equivalent example using anonymous background thread:
procedure TForm1.Button1Click(Sender: TObject);
begin
TThread.CreateAnonymousThread(
procedure
var
httpclient: TNetHTTPClient;
output: string;
begin
httpclient := TNetHTTPClient.Create(nil);
try
httpclient.Asynchronous := False;
output := httpclient.Get('https://google.com').ContentAsString;
finally
httpclient.Free;
end;
end).Start;
end;
Of course, you can also use TTask
or custom threads instead of anonymous threads.
Upvotes: 5