Delphi - TIdHTTP 在发布数据时冻结
Delphi - TIdHTTP freezes when POSTing data
我在使用 Indy 的 TIdHTTP
组件开发 HTTP 客户端时遇到问题。我正在使用 Indy 10.5.9.0.
当我调用 TIdHTTP.DoRequest()
方法时,组件冻结并引发异常:
Connection closed gracefully
我已经尝试使用 TIdHTTP.Post()
方法,但出现了同样的问题。
使用 TIdHTTP.Get()
方法不会出现此问题。
这是我的代码:
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;
谁能帮我解决这个问题?
I'm using Indy 10.5.9.0.
那是一个非常古老和过时的版本。在撰写本文时,最新版本为 10.6.2.5455。 Please upgrade,因为自 10.5.9 以来对 Indy 进行了大量更改和修复。
When I call the TIdHTTP.Post()
method, the component freezes, and raises an exception:
首先,你不是在调用TIdHTTP.Post()
,你是在调用TIdHTTP.DoRequest()
。您应该改为调用 TIdHTTP.Post()
,它会在内部为您调用 TIdHTTP.DoRequest()
:
httpClient.Post(srv, JsonToSend, jsonRetorno);
其次,Post()
不能同时冻结和引发异常。到底发生了什么?您 post 的 JSON 有多大?在引发异常之前服务器是否发送任何类型的响应?
第三,你绝对根本不应该调用TIdHTTP.SetRequestParams()
。当 TIdHTTP.Post()
以 application/x-www-webform-urlencoded
格式提交 HTML 网络表单时,该方法供 TStrings
重载版本内部使用。在这种情况下,这不是您所需要的。您需要按原样 post 您的 JSON,而不是对其进行 webform 编码。
Indy 使用阻塞套接字。 Indy 中的大多数操作都是同步的。 TIdHTTP.Post()
也不例外。它会阻塞调用线程,直到 HTTP post 完成。如果它冻结,则意味着 post 需要很长时间才能发送,或者服务器没有发回有效响应。如果 TIdHTTP.Post()
引发 "Connection closed gracefully" 异常,这意味着服务器已关闭其端的套接字连接,而 TIdHTTP
仍在套接字上 sending/reading 数据。这可能会发生,例如,如果服务器不喜欢您的 POST
请求,或者如果它确定 JSON 在接收时无效。
此外,您的代码总体上可以简化。您滥用 TStringList
来处理 JSON 数据。
尝试更像这样的东西:
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;
我在使用 Indy 的 TIdHTTP
组件开发 HTTP 客户端时遇到问题。我正在使用 Indy 10.5.9.0.
当我调用 TIdHTTP.DoRequest()
方法时,组件冻结并引发异常:
Connection closed gracefully
我已经尝试使用 TIdHTTP.Post()
方法,但出现了同样的问题。
使用 TIdHTTP.Get()
方法不会出现此问题。
这是我的代码:
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;
谁能帮我解决这个问题?
I'm using Indy 10.5.9.0.
那是一个非常古老和过时的版本。在撰写本文时,最新版本为 10.6.2.5455。 Please upgrade,因为自 10.5.9 以来对 Indy 进行了大量更改和修复。
When I call the
TIdHTTP.Post()
method, the component freezes, and raises an exception:
首先,你不是在调用TIdHTTP.Post()
,你是在调用TIdHTTP.DoRequest()
。您应该改为调用 TIdHTTP.Post()
,它会在内部为您调用 TIdHTTP.DoRequest()
:
httpClient.Post(srv, JsonToSend, jsonRetorno);
其次,Post()
不能同时冻结和引发异常。到底发生了什么?您 post 的 JSON 有多大?在引发异常之前服务器是否发送任何类型的响应?
第三,你绝对根本不应该调用TIdHTTP.SetRequestParams()
。当 TIdHTTP.Post()
以 application/x-www-webform-urlencoded
格式提交 HTML 网络表单时,该方法供 TStrings
重载版本内部使用。在这种情况下,这不是您所需要的。您需要按原样 post 您的 JSON,而不是对其进行 webform 编码。
Indy 使用阻塞套接字。 Indy 中的大多数操作都是同步的。 TIdHTTP.Post()
也不例外。它会阻塞调用线程,直到 HTTP post 完成。如果它冻结,则意味着 post 需要很长时间才能发送,或者服务器没有发回有效响应。如果 TIdHTTP.Post()
引发 "Connection closed gracefully" 异常,这意味着服务器已关闭其端的套接字连接,而 TIdHTTP
仍在套接字上 sending/reading 数据。这可能会发生,例如,如果服务器不喜欢您的 POST
请求,或者如果它确定 JSON 在接收时无效。
此外,您的代码总体上可以简化。您滥用 TStringList
来处理 JSON 数据。
尝试更像这样的东西:
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;