在 Delphi 中使用 TIdHTTP 来模拟 curl 命令

use TIdHTTP in Delphi to simulate curl command

我正在尝试使用 IdHTTP 来等效于以下 curl 操作:

curl -X POST -F "message=@C:\Users\santon\Desktop\ESM_download\token.txt" "https://esm-db.eu/esmws/eventdata/1/query?eventid=IT-1997-0004&station=CLF&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:\Users\santon\Desktop\ESM_download\token.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-0004&station=CLF&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 禁止错误。 对我做错了什么有什么想法吗?

提前致谢

您没有将令牌文件正确加载到 TIdMultiPartFormDataStream

根据 curl 文档:

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

-F, --form <name=content>

(HTTP SMTP IMAP) For HTTP protocol family, this lets curl emulate a filled-in form in which a user has pressed the submit button. This causes curl to POST data using the Content-Type multipart/form-data according to RFC 2388.

...

This enables uploading of binary files etc. To force the 'content' part to be a file, prefix the file name with an @ sign. To just get the content part from a file, prefix the file name with the symbol <. The difference between @ and < is then that @ makes a file get attached in the post as a file upload, while the < makes a text field and just get the contents for that text field from a file.

...

Example: send an image to an HTTP server, where 'profile' is the name of the form-field to which the file portrait.jpg will be the input:

 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:\Users\santon\Desktop\ESM_download\token.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-0004&station=CLF&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;