问题描述
我正在尝试使用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
总是处理完整的流/文件(因为参数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:
推荐答案
正如我在,您必须发布TStream
,其中包含要上传的剩余文件数据.不要使用TIdMultipartFormDataStream.AddFile()
,因为那样会发送整个文件.请使用TIdMultipartFormDataStream.AddFormField()
的TStream
重载版本.
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发布/上传的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!