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