2012-03-07 31 views
3

我想繼續使用印(HTTP郵政)上傳/上傳,代碼如下所示(使用德爾福2010年,印10.4736):恢復HTTP郵政與印

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 

但上傳簡歷沒有「T工作:(

我看着Indy的代碼,似乎這個功能IdIOHandler.pas

TIdIOHandler.Write()

總是處理完整的流/文件(因爲參數ASize:TIdStreamSize似乎總是0,根據代碼意味着發送完整的文件/流)。

這可以防止indy恢復上傳。

我的問題是:是否可以避免發送完整的文件?

設置內容範圍沒有改變任何東西。我還調整了Indy的代碼(修改後的3線),使印服從的含量範圍/流的位置,但它是越野車和印地最後總是掛在IdStackWindows.pas因爲無限超時這裏:

TIdSocketListWindows.FDSelect()

+0

你應該爲此使用'PUT'。 – OnTheFly 2012-03-07 13:23:12

+0

這裏是雷米勒博[說一下放](http://stackoverflow.com/questions/9476744/how-to-optimize-upload-routine-using-delphi-2010#comment12034421_9492180) – TheDude 2012-03-07 13:56:44

+0

不知道,他大概在PHP4會談。但是,是的,你的願望與POST不兼容。 – OnTheFly 2012-03-07 14:56:05

回答

4

正如我告訴你your earlier question,你必須張貼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()像我suggested earlier,如:

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; 

我已經explained earlier如何訪問PHP原始POST數據。

+0

我很抱歉,但在您上一篇文章中並不清楚。此外,我使用TIdMultipartFormDataStream的原因是因爲它可以處理非常好的大文件。這種解決方案意味着必須分割/複製文件(這可能會減慢大文件情況下的進程)並且正好相反。 – TheDude 2012-03-07 13:54:47

+0

感謝您的額外幫助,我認爲更新indy以支持恢復上傳並不是一個壞主意,但您知道比我更好的indy/http。 – TheDude 2012-03-07 13:54:58

+2

正如我前面解釋的那樣,你不需要也不應該分裂文件。發佈一個'TIdMultipartFormDataStream'與一個普通的'TStream'對於你正在嘗試做的事情來說太過於誇張了。發佈一個普通的'TStream'可以處理大文件,就像發佈'TIdMultipartFormDataStream'一樣好,如果不能處理所有額外的開銷。正如我之前解釋的那樣,** HTTP本身不支持上傳恢復**,因此您使用的任何解決方案都將成爲黑客,因爲您必須編寫後端PHP腳本以手動支持它。 – 2012-03-07 17:31:06