Delphi - TIdHTTP在发布数据时冻结

时间:2018-05-03 19:34:13

标签: delphi indy delphi-xe3 indy10 idhttp

使用Indy的TIdHTTP组件开发HTTP客户端时遇到问题。我正在使用Indy 10.5.9.0。

当我调用TIdHTTP.DoRequest()方法时,组件会冻结,并引发异常:

  

连接正常关闭

我已尝试使用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;

任何人都可以帮我解决这个问题吗?

1 个答案:

答案 0 :(得分:2)

  

我正在使用Indy 10.5.9.0。

这是一个非常陈旧且过时的版本。在撰写本文时,最新版本是10.6.2.5455。 Please upgrade,因为10.5.9以来对Indy进行了很多修改和修复。

  

当我调用TIdHTTP.Post()方法时,组件会冻结,并引发异常:

首先,您没有致电TIdHTTP.Post(),而是致电TIdHTTP.DoRequest()。您应该拨打TIdHTTP.Post(),而在内部为您调用TIdHTTP.DoRequest()

httpClient.Post(srv, JsonToSend, jsonRetorno);

其次,Post()无法同时冻结并引发异常。实际上发生了什么?你发布的JSON有多大?服务器是否在引发异常之前发送任何类型的响应?

第三,你绝对根本不应该调用TIdHTTP.SetRequestParams()。当TStrings以#{1}}格式提交HTML网络表单时,该方法仅供TIdHTTP.Post()重载版application/x-www-webform-urlencoded内部使用。这不是你在这种情况下所需要的。您需要按原样发布JSON,而不是对其进行webform编码。

Indy使用阻塞套接字。 Indy的大多数操作都是同步的。 TIdHTTP.Post()也不例外。它阻止调用线程,直到HTTP帖子完成。如果它冻结,这意味着帖子需要很长时间才能发送,或者服务器没有发回有效的响应。如果TIdHTTP.Post()引发“正常关闭连接”异常,则意味着服务器已在其TIdHTTP仍通过套接字发送/读取数据时关闭了套接字连接。例如,如果服务器不喜欢您的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;