基于 curl 调用使用 IdHTTP 将文件上传到指定主机

Upload file using IdHTTP to specified host based on curl call

我正在尝试创建需要将文件上传到给定主机的 FMX Android 应用程序。

主机所有者向我提供了以下 curl 声明来上传文件:

curl -T http://<ip-address>:<port> file.txt

当从 Windows 命令提示符调用时,它会产生以下输出(已编辑 IP 和端口):

*   Trying <ip-address>...
* TCP_NODELAY set
* Connected to <ip-address> (<ip-address>) port <port> (#0)
> PUT /file.txt HTTP/1.1
> Host: <ip-address>:<port>
> User-Agent: curl/7.55.1
> Accept: */*
> Content-Length: 682
> Expect: 100-continue
>
* Done waiting for 100-continue
* We are completely uploaded and fine
< HTTP/1.1 200 OK
< content-length: 0
< date: Tue, 16 Jun 2020 19:24:18 GMT
< connection: close
<
* Closing connection 0

并且文件在主机上的预期目录中可见。

现在我正在尝试使用 Indy 实现相同的行为,但要么是服务器端发生了一些黑盒魔法,要么是我的代码存在问题 - 对于某些解决方案,请求似乎finalize,但指定目录下没有文件(返回状态码200)。

我也尝试过使用 Fiddler 重现 curl 调用,并且在组合查询的响应中也收到了 200 状态代码,但仍然没有文件被正确上传。

在检查这些解决方案的 Wireshark 数据包时,它们看起来都类似于 curl 调用 - 但是,我不是使用此工具的专家,所以可能有些问题我的新手看不到。

我尝试使用以下解决方案:
- - 但使用 PUT 而不是 POST
- Single file upload example
-

在我的情况下它们不起作用 - 所以我猜测服务器不知何故不接受这些。

我知道如果我没有实际输入一些代码很难说出我做错了什么,但现在它一团糟 - 但也许不难告诉我如何将这个 curl 调用转换为工作TIdHttp?

如果没有,我会尝试尽快用更多信息修改我的问题。

编辑: 根据要求,我添加了一些示例代码:

var
  FHTTP: TIdHTTP;
  file2send: string;
  sr: TStringStream;
  FPutData : TFileStream;
begin
  sr := TStringStream.Create;
  if OpenDialog1.Execute then
    file2send := OpenDialog1.FileName;

  FHTTP := TIdHTTP.Create(self);
  FPutData := TFileStream.Create(file2send, fmOpenRead or
    fmShareDenyWrite);
  FHTTP.Put(PutURL.text, FPutData, sr);

end;

您不需要 TStringStream,因为您不使用它。您可以在该参数中传递 TStream(nil)

此外,即使 OpenDialog.Execute() returns false,您也无条件调用 FHTTP.Put()

此外,请确保您传递给 FHTTP.Put() 的 URL 是 'http://<ip-address>:<port>/file.txt' 而不是 'http://<ip-address>:<port>'

此外,考虑设置 FHTTP.Request.UserAgent,因为一些 Web 服务器拒绝 Indy 的默认值 UserAgent

此外,请考虑 Free 处理您的对象,特别是如果您计划升级到 10.4 Sydney 或更高版本,因为用于对象生命周期管理的 ARC 在 10.4 中已被删除。

试试像这样的东西:

var
  FHTTP: TIdHTTP;
  file2send: string;
  FPutData : TFileStream;
begin
  if not OpenDialog1.Execute then Exit;

  file2send := OpenDialog1.FileName;

  FHTTP := TIdHTTP.Create(nil);
  try
    FHTTP.Request.UserAgent := 'curl/7.55.1';
    FPutData := TFileStream.Create(file2send, fmOpenRead or fmShareDenyWrite);
    try
      FHTTP.Put(PutURL.Text, FPutData, TStream(nil));
      { or, maybe something like:
      URL := PutURL.Text + '/' + ExtractFileName(file2send);
      FHTTP.Put(URL, FPutData, TStream(nil));
      }
    finally
      FPutData.Free;
    end;
  finally
    FHTTP.Free;
  end;
end;