[英]Resume HTTP Post/upload with Indy
I'm trying to resume an upload using indy (HTTP Post), the code looks like this (using Delphi 2010, Indy 10.4736): 我正在尝试使用indy(HTTP Post)恢复上传,代码看起来像这样(使用Delphi 2010,Indy 10.4736):
IdHttp.Head('http://localhost/_tests/resume/large-file.bin');
ByteRange := IdHttp.Response.ContentLength + 1;
// Attach the file to post/upload
Stream := TIdMultipartFormDataStream.Create;
with Stream.AddFile('upload_file', 'D:\large-file.bin', 'application/octet-stream') do
begin
HeaderCharset := 'utf-8';
HeaderEncoding := '8';
end; // with
with IdHTTP do
begin
IOHandler.LargeStream := True;
with Request do
begin
ContentRangeStart := ByteRange;
ContentRangeEnd := (Stream.Size - ByteRange);
ContentLength := ContentRangeEnd;
ContentRangeInstanceLength := ContentLength;
end; // with
Post('http://localhost/_tests/resume/t1.php', Stream);
end; // with
but upload resume doesn't work :( 但上传简历不起作用:(
I looked into Indy's code, it seems that this function in IdIOHandler.pas 我调查了Indy的代码,看来这个函数在IdIOHandler.pas中
TIdIOHandler.Write() TIdIOHandler.Write()
always deal with complete streams/files (since the parameter ASize: TIdStreamSize seems to be always 0, which according to the code means sending the full file/stream). 总是处理完整的流/文件(因为参数ASize:TIdStreamSize似乎总是0,根据代码意味着发送完整的文件/流)。
This prevents indy from resuming the upload. 这可以防止indy恢复上传。
My question is: is it possible to avoid sending the full file? 我的问题是:是否可以避免发送完整文件?
Setting content range didn't change anything. 设置内容范围没有任何改变。 I also tweaked indy's code (modified 3 lines) to make indy obey to the content range / stream position, but it's buggy and indy always end up hanging in IdStackWindows.pas because of an infinite timeout here: 我还调整了indy的代码(修改了3行),使indy服从内容范围/流的位置,但它的bug和indy总是最终挂在IdStackWindows.pas中,因为这里有无限超时:
TIdSocketListWindows.FDSelect() TIdSocketListWindows.FDSelect()
As I told you in your earlier question , you have to post a TStream
containing the remaining file data to upload. 正如我在您之前的问题中告诉您的那样 ,您必须发布一个包含要上传的剩余文件数据的TStream
。 Don't use TIdMultipartFormDataStream.AddFile()
, as that will send the entire file. 不要使用TIdMultipartFormDataStream.AddFile()
,因为它将发送整个文件。 Use the TStream
overloaded version of TIdMultipartFormDataStream.AddFormField()
instead. 请改用TStream
重载版本的TIdMultipartFormDataStream.AddFormField()
。
And TIdHTTP
is not designed to respect the ContentRange...
properties. 并且TIdHTTP
不是为了尊重ContentRange...
属性而设计的。 Most of the Request
properties merely set the corresponding HTTP headers only, they do not influence the data. 大多数Request
属性仅设置相应的HTTP标头,它们不会影响数据。 That is why your edits broke it. 这就是为什么你的编辑打破了它。
Try this: 试试这个:
IdHttp.Head('http://localhost/_tests/resume/large-file.bin');
FileSize := IdHttp.Response.ContentLength;
FileStrm := TFileStream.Create('D:\large-file.bin', fmOpenRead or fmShareDenyWrite);
try
if FileSize < FileStrm.Size then
begin
FileStrm.Position := FileSize;
Stream := TIdMultipartFormDataStream.Create;
try
with Stream.AddFormField('upload_file', 'application/octet-stream', '', FileStrm, 'large-file.bin') do
begin
HeaderCharset := 'utf-8';
HeaderEncoding := '8';
end;
with IdHTTP do
begin
with Request do
begin
ContentRangeStart := FileSize + 1;
ContentRangeEnd := FileStrm.Size;
end;
Post('http://localhost/_tests/resume/t1.php', Stream);
end;
finally
Stream.Free;
end;
end;
finally
FileStrm.Free;
end;
With that said, this is a GROSS MISUSE of HTTP and multipart/form-data
. 话虽如此,这是HTTP和multipart/form-data
重大错误 。 For starters, the ContentRange
values are in the wrong place. 对于初学者, ContentRange
值位于错误的位置。 You are applying them to the entire Request
as a whole, which is wrong. 您将它们作为一个整体应用于整个Request
,这是错误的。 They would need to be applied at the FormField
instead, but TIdMultipartFormDataStream
does not currently support that. 它们需要在FormField
应用,但TIdMultipartFormDataStream
目前不支持。 Second, multipart/form-data
was not designed to be used like this anyway. 其次, multipart/form-data
并不是设计成这样使用的。 It is fine for uploading a file from the beginning, but not for resuming a broken upload. 它可以从一开始就上传文件,但不能用于恢复损坏的上传。 You really should stop using TIdMultipartFormDataStream
and just pass the file data directly to TIdHTTP.Post()
like I suggested earlier , eg: 你真的应该停止使用TIdMultipartFormDataStream
并将文件数据直接传递给TIdHTTP.Post()
就像我之前建议的那样 ,例如:
FileStrm := TFileStream.Create('D:\large-file.bin', fmOpenRead or fmShareDenyWrite);
try
IdHTTP.Post('http://localhost/_tests/upload.php?name=large-file.bin', FileStrm);
finally
FileStrm.Free;
end;
. 。
IdHTTP.Head('http://localhost/_tests/files/large-file.bin');
FileSize := IdHTTP.Response.ContentLength;
FileStrm := TFileStream.Create('D:\large-file.bin', fmOpenRead or fmShareDenyWrite);
try
if FileSize < FileStrm.Size then
begin
FileStrm.Position := FileSize;
IdHTTP.Post('http://localhost/_tests/resume.php?name=large-file.bin', FileStrm);
end;
finally
FileStrm.Free;
end;
I already explained earlier how to access the raw POST
data in PHP. 我之前已经解释过如何在PHP中访问原始POST
数据。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.