基于 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;
我正在尝试创建需要将文件上传到给定主机的 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;