используйте TIdHTTP в Delphi для имитации команды curl

#delphi #curl #indy

#delphi #curl #indy

Вопрос:

Я пытаюсь использовать IdHTTP для эквивалентности следующей операции curl:

 curl -X POST -F "message=@C:UserssantonDesktopESM_downloadtoken.txt" "https://esm-db.eu/esmws/eventdata/1/query?eventid=IT-1997-0004amp;station=CLFamp;format=ascii" -o RecordFileName.zip
  

Команда curl используется для загрузки файла с сервера, который затем сохраняется на жестком диске как DownloadedFileName.zip . Требуется авторизация через файл токена на жестком диске, называемый token.txt . Путь к файлу токена указывается в качестве параметра curl.
Лучшее, что я мог сделать, это следующий код:

 procedure TMainForm.HTTPGetFile;
var
  IdHTTP: TIdHTTP;
  Params: TIdMultipartFormDataStream;
  LHandler: TIdSSLIOHandlerSocketOpenSSL;
begin
  try
    Params := TIdMultipartFormDataStream.Create;
    Params.AddFormField('message', '@"C:UserssantonDesktopESM_downloadtoken.txt"');

      IdHTTP := TIdHTTP.Create(nil);
      LHandler:= TIdSSLIOHandlerSocketOpenSSL.Create(self);
      LHandler.SSLOptions.Method := sslvTLSv1;
      try
        IdHTTP.IOHandler := LHandler;
        IdHTTP.Post('https://esm-db.eu/esmws/eventdata/1/query?eventid=IT-1997-0004amp;station=CLFamp;format=ascii',Params);
      finally
        IdHTTP.Free;
        LHandler.Free;
        Params.Free;
      end;
  except
    on E: Exception do
      ShowMessage('Error: ' E.ToString);
  end;
end;
  

Но я продолжаю получать запрещенную ошибку HTTP / 1.1 403.
Есть идеи о том, что я делаю неправильно?

Заранее спасибо

Комментарии:

1. Почему бы вам просто не вызвать curl из своего приложения?

Ответ №1:

Вы неправильно загружаете файл токена TIdMultiPartFormDataStream .

Согласно документации curl:

https://curl.se/docs/manpage.html#-F

-F, —form <имя=содержимое>

(HTTP SMTP IMAP) Для семейства протоколов HTTP это позволяет curl эмулировать заполненную форму, в которой пользователь нажал кнопку отправки. Это приводит к тому, что curl отправляет данные, используя составные данные типа содержимого / формы в соответствии с RFC 2388.

Это позволяет загружать двоичные файлы и т. Д. Чтобы заставить часть «содержимого» быть файлом, префикс имени файла со знаком @ .Чтобы просто получить часть содержимого из файла, добавьте к имени файла символ < . Разница между @ и < заключается в том, что @ делает файл прикрепленным к сообщению в качестве загрузки файла, в то время как < создает текстовое поле и просто получает содержимое этого текстового поля из файла.

Пример: отправьте изображение на HTTP-сервер, где ‘profile’ — это имя поля формы, в которое передается файл. portrait.jpg будет являться входным сигналом:

curl -F profile=@portrait.jpg https://example.com/upload.cgi

В вашем коде вы создаете текстовое поле, содержимым которого является само имя файла. Вы не создаете поле загрузки файла, содержимым которого являются данные из файла.

Попробуйте это вместо:

 procedure TMainForm.HTTPGetFile;
var
  IdHTTP: TIdHTTP;
  Params: TIdMultipartFormDataStream;
  LHandler: TIdSSLIOHandlerSocketOpenSSL;
  LOutFile: TFileStream;
begin
  try
    Params := TIdMultipartFormDataStream.Create;
    try
      Params.AddFile('message', 'C:UserssantonDesktopESM_downloadtoken.txt');

      IdHTTP := TIdHTTP.Create(nil);
      try
        LHandler := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
        LHandler.SSLOptions.Method := sslvTLSv1;
        IdHTTP.IOHandler := LHandler;

        LOutFile := TFileStream.Create('<path>RecordFileName.zip', fmCreate);
        try
          IdHTTP.Post('https://esm-db.eu/esmws/eventdata/1/query?eventid=IT-1997-0004amp;station=CLFamp;format=ascii', Params, LOutFile);
        finally
          LOutFile.Free;
        end;
      finally
        IdHTTP.Free;
      end;
    finally
      Params.Free;
    end;
  except
    on E: Exception do
      ShowMessage('Error: '   E.ToString);
  end;
end;
  

Комментарии:

1. Большое спасибо, Реми Лебо! Это отлично работает с одним небольшим изменением: команда addFile должна иметь пустой строковый аргумент в конце, чтобы скомпилировать: Params . addFile(‘сообщение’, ‘C:UserssantonDesktopESM_downloadtoken.txt ‘,»); Стелиос

2. 3-й параметр AddFile() имеет значение по умолчанию '' ( function AddFile(const AFieldName, AFileName: String; const AContentType: string = ''): TIdFormDataField; ) , поэтому вам не нужно указывать это '' явно. Если ваш компилятор требует этого, то вы, вероятно, используете более старую версию Indy, которая не имеет значения параметра по умолчанию и должна обновиться до последней версии.

3. Еще раз спасибо! Я использую Indy 10.5.7.

4. @SteliosAntoniou это старая версия. Текущая версия — 10.6.2