I have an issue developing an HTTP client using Indy's TIdHTTP
component. I'm using Indy 10.5.9.0.
When I call the TIdHTTP.DoRequest()
method, the component freezes, and raises an exception:
Connection closed gracefully
I already tried using the TIdHTTP.Post()
method, but the same problem happens.
The problem doesn't happen using the TIdHTTP.Get()
method.
Here is my code:
try
jsonLatestFirmware := TJSONObject.ParseJSONValue(httpClient.Get(strGetLatest)) as TJSONObject;
try
srv := 'http://' + currentAlive.IP + ':9335/upgrade?command=start';
sList := TStringList.Create;
sList.Text := jsonLatestFirmware.get('data').JsonValue.ToString;
fileName := ExtractFilePath(Application.ExeName) + 'finals\' + currentMACQR + '-' + currentAlive.IP + '.json';
sList.SaveToFile(fileName);
JsonRetorno := TStringStream.Create('');
try
JsonToSend := TStringStream.Create;
WriteStringToStream(JsonToSend,TIdHTTPAccess(httpClient).SetRequestParams(sList, TEncoding.UTF8));
JsonToSend.Position := 0;
TIdHTTPAccess(httpClient).DoRequest('POST',srv,JsonToSend,jsonRetorno,[]); //component freezes here...
strRetorno := TStringList.Create();
strRetorno.LoadFromStream(JsonRetorno);
lblInformacao.Visible := True;
ShowMessage(strRetorno.Text);
except
on E: Exception do
ShowMessage('Error on request: '#13#10 + E.Message);
end;
finally
sList.Free;
JsonRetorno.Free;
JsonToSend.Free;
jsonResponse.Free;
end;
except
on E: Exception do
ShowMessage('There are no firmwares available for this product.');
end;
Anyone can help me to solve this problem?
I'm using Indy 10.5.9.0.
That is a very old and outdated version. At the time of this writing, the latest version is 10.6.2.5455. Please upgrade, as there have been a lot of changes and fixes to Indy since 10.5.9.
When I call the
TIdHTTP.Post()
method, the component freezes, and raises an exception:
First, you are not calling TIdHTTP.Post()
, you are calling TIdHTTP.DoRequest()
. You should be calling TIdHTTP.Post()
instead, which calls TIdHTTP.DoRequest()
internally for you:
httpClient.Post(srv, JsonToSend, jsonRetorno);
Second, Post()
can't freeze and raise an exception at the same time. Which is actually happening? How large is the JSON you are posting? Does the server send any kind of response before the exception is raised?
Third, you absolutely should NOT be calling TIdHTTP.SetRequestParams()
at all. That method is meant for internal use by the TStrings
overloaded version of TIdHTTP.Post()
when it submits an HTML webform in application/x-www-webform-urlencoded
format. That is NOT what you need in this situation. You need to post your JSON as-is, not webform-encode it.
Indy uses blocking sockets. Most operations in Indy are synchronous. TIdHTTP.Post()
is no different. It blocks the calling thread until the HTTP post is finished. If it freezes, that means the post is taking a long time to send, or the server is not sending a valid response back. If TIdHTTP.Post()
raises a "Connection closed gracefully" exception, that means the server has closed the socket connection on its end while TIdHTTP
was still sending/reading data over the socket. That could happen, for instance, if the server doesn't like your POST
request, or if it determines the JSON is invalid while it is being received.
Also, your code can be simplified in general. You are misusing TStringList
for handling JSON data.
Try something more like this instead:
var
sJSON, sRetorno: string;
jsonLatestFirmware: TJSONValue;
JsonToSend: TStringStream;
...
begin
...
try
sJSON := httpClient.Get(strGetLatest);
except
ShowMessage('There are no firmwares available for this product.');
Exit;
end;
try
jsonLatestFirmware := TJSONObject.ParseJSONValue(sJSON);
try
sJson := (jsonLatestFirmware as TJSONObject).get('data').JsonValue.ToString;
finally
jsonLatestFirmware.Free;
end;
JsonToSend := TStringStream.Create(sJson, TEncoding.UTF8);
try
JsonToSend.SaveToFile(ExtractFilePath(Application.ExeName) + 'finals\' + currentMACQR + '-' + currentAlive.IP + '.json');
httpClient.Request.ContentType := 'application/json';
sRetorno := httpClient.Post('http://' + currentAlive.IP + ':9335/upgrade?command=start', JsonToSend);
finally
JsonToSend.Free;
end;
except
on E: Exception do
ShowMessage('Error: '#13#10 + E.Message);
Exit;
end;
lblInformacao.Visible := True;
ShowMessage(sRetorno);
...
end;