Delphi - TIdHTTP зависает при отправке данных - PullRequest
0 голосов
/ 03 мая 2018

У меня проблема с разработкой HTTP-клиента с использованием компонента TIdHTTP в Indy. Я использую 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 голосов
/ 03 мая 2018

Я использую Indy 10.5.9.0.

Это очень старая и устаревшая версия. На момент написания этой статьи последняя версия - 10.6.2.5455. Пожалуйста, обновите , так как было много изменений и исправлений в Indy с 10.5.9.

Когда я вызываю метод TIdHTTP.Post(), компонент зависает и вызывает исключение:

Во-первых, вы не звоните TIdHTTP.Post(), вы звоните TIdHTTP.DoRequest(). Вместо этого вы должны звонить TIdHTTP.Post(), что для вас вызывает TIdHTTP.DoRequest():

httpClient.Post(srv, JsonToSend, jsonRetorno);

Во-вторых, Post() не может замерзнуть и вызвать исключение одновременно. Что на самом деле происходит? Насколько велик JSON, который вы публикуете? Отправляет ли сервер какой-либо ответ до возникновения исключения?

В-третьих, вы абсолютно НЕ должны вообще звонить TIdHTTP.SetRequestParams(). Этот метод предназначен для внутреннего использования перегруженной версией TStrings TIdHTTP.Post(), когда он отправляет веб-форму HTML в формате application/x-www-webform-urlencoded. Это НЕ то, что вам нужно в этой ситуации. Вы должны опубликовать свой JSON как есть, а не кодировать его в веб-форме.

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;
...