繁体   English   中英

使用Indy恢复HTTP发布/上传

[英]Resume HTTP Post/upload with Indy

我正在尝试使用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

但上传简历不起作用:(

我调查了Indy的代码,看来这个函数在IdIOHandler.pas中

TIdIOHandler.Write()

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

这可以防止indy恢复上传。

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

设置内容范围没有任何改变。 我还调整了indy的代码(修改了3行),使indy服从内容范围/流的位置,但它的bug和indy总是最终挂在IdStackWindows.pas中,因为这里有无限超时:

TIdSocketListWindows.FDSelect()

正如我在您之前的问题中告诉您的那样 ,您必须发布一个包含要上传的剩余文件数据的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()就像我之前建议的那样 ,例如:

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;

我之前已经解释过如何在PHP中访问原始POST数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM