简体   繁体   English

使用Indy恢复HTTP发布/上传

[英]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.

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