2012-03-07 30 views
3

我想继续使用印(HTTP邮政)上传/上传,代码如下所示(使用德尔福2010年,印10.4736):恢复HTTP邮政与印

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 

但上传简历没有“T工作:(

我看着Indy的代码,似乎这个功能IdIOHandler.pas

TIdIOHandler.Write()

总是处理完整的流/文件(因为参数ASize:TIdStreamSize似乎总是0,根据代码意味着发送完整的文件/流)。

这可以防止indy恢复上传。

我的问题是:是否可以避免发送完整的文件?

设置内容范围没有改变任何东西。我还调整了Indy的代码(修改后的3线),使印服从的含量范围/流的位置,但它是越野车和印地最后总是挂在IdStackWindows.pas因为无限超时这里:

TIdSocketListWindows.FDSelect()

+0

你应该为此使用'PUT'。 – OnTheFly 2012-03-07 13:23:12

+0

这里是雷米勒博[说一下放](http://stackoverflow.com/questions/9476744/how-to-optimize-upload-routine-using-delphi-2010#comment12034421_9492180) – TheDude 2012-03-07 13:56:44

+0

不知道,他大概在PHP4会谈。但是,是的,你的愿望与POST不兼容。 – OnTheFly 2012-03-07 14:56:05

回答

4

正如我告诉你your earlier question,你必须张贴TStream包含其余文件数据上传。不要使用TIdMultipartFormDataStream.AddFile(),因为它会发送整个文件。改为使用TStream重载版本TIdMultipartFormDataStream.AddFormField()

TIdHTTP并不旨在尊重ContentRange...属性。大多数Request属性仅仅设置相应的HTTP标头,它们不影响数据。这就是为什么你的编辑打破了它。

试试这个:

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; 

随着中说,这是一个重大的错误使用HTTP和multipart/form-data。对于初学者,ContentRange值是错误的地方。整体而言,您将它们应用于整个Request,这是错误的。他们需要在FormField上应用,但TIdMultipartFormDataStream目前不支持该功能。其次,multipart/form-data的设计并非像这样使用。从头开始上传文件是好的,但不能恢复上传的文件。你真的应该停止使用TIdMultipartFormDataStream而直接传递文件数据TIdHTTP.Post()像我suggested earlier,如:

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; 

我已经explained earlier如何访问PHP原始POST数据。

+0

我很抱歉,但在您上一篇文章中并不清楚。此外,我使用TIdMultipartFormDataStream的原因是因为它可以处理非常好的大文件。这种解决方案意味着必须分割/复制文件(这可能会减慢大文件情况下的进程)并且正好相反。 – TheDude 2012-03-07 13:54:47

+0

感谢您的额外帮助,我认为更新indy以支持恢复上传并不是一个坏主意,但您知道比我更好的indy/http。 – TheDude 2012-03-07 13:54:58

+2

正如我前面解释的那样,你不需要也不应该分裂文件。发布一个'TIdMultipartFormDataStream'与一个普通的'TStream'对于你正在尝试做的事情来说太过于夸张了。发布一个普通的'TStream'可以处理大文件,就像发布'TIdMultipartFormDataStream'一样好,如果不能处理所有额外的开销。正如我之前解释的那样,** HTTP本身不支持上传恢复**,因此您使用的任何解决方案都将成为黑客,因为您必须编写后端PHP脚本以手动支持它。 – 2012-03-07 17:31:06