使用Indy恢复HTTP发布/上传 [英] Resume HTTP Post/upload with Indy

查看:114
本文介绍了使用Indy恢复HTTP发布/上传的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用indy(HTTP发布)恢复上传,代码看起来像这样(使用Delphi 2010,Indy 10.4736):

I'm trying to resume an upload using indy (HTTP Post), the code looks like this (using 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 :(

我查看了Indy的代码,似乎该函数在 IdIOHandler.pas

I looked into Indy's code, it seems that this function in IdIOHandler.pas

TIdIOHandler.Write()

TIdIOHandler.Write()

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

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).

这可以防止indy恢复上载.

This prevents indy from resuming the upload.

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

My question is: is it possible to avoid sending the full file?

设置内容范围没有任何改变.我还调整了indy的代码(修改了3行),使indy服从内容范围/流的位置,但是它的越野车和indy总是由于以下无限超时而最终挂在 IdStackWindows.pas 上: /p>

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:

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. Don't use TIdMultipartFormDataStream.AddFile(), as that will send the entire file. Use the TStream overloaded version of TIdMultipartFormDataStream.AddFormField() instead.

TIdHTTP的设计不尊重ContentRange...属性.大多数Request属性仅设置相应的HTTP标头,它们不影响数据.这就是为什么您的编辑破坏了它的原因.

And TIdHTTP is not designed to respect the ContentRange... properties. Most of the Request properties merely set the corresponding HTTP headers only, they do not influence the data. That is why your edits broke it.

尝试一下:

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(),就像我

With that said, this is a GROSS MISUSE of HTTP and multipart/form-data. For starters, the ContentRange values are in the wrong place. You are applying them to the entire Request as a whole, which is wrong. They would need to be applied at the FormField instead, but TIdMultipartFormDataStream does not currently support that. Second, multipart/form-data was not designed to be used like this anyway. 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:

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;

我已经早先解释了如何访问原始文件POST PHP中的数据.

I already explained earlier how to access the raw POST data in PHP.

这篇关于使用Indy恢复HTTP发布/上传的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆