2009-06-29 71 views
3

修訂如下大文件上傳(引發WebException:連接被意外關閉)

看帖子​​。

需要自動將文件上傳到網絡(無瀏覽器)。主機 - Mini File Host v1.2(如果這很重要)。沒有找到具體的API中的文件,所以起初我在Firebug嗅到瀏覽器請求如下:

Params : do 
Value : verify 
POST /upload.php?do=verify HTTP/1.1 
Host: webfile.ukrwest.net 
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.2; ru; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8 (.NET CLR 4.0.20506) 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: ru,en-us;q=0.7,en;q=0.3 
Accept-Encoding: gzip,deflate 
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7 
Keep-Alive: 300 
Connection: keep-alive 
Referer: http://filehoster.awardspace.com/index.php 
Content-Type: multipart/form-data; boundary=---------------------------27368237179714 
Content-Length: 445 

-----------------------------27368237179714 
Content-Disposition: form-data; name="upfile"; filename="Test.file" 
Content-Type: application/octet-stream 

12345678901011121314151617sample text 
-----------------------------27368237179714 
Content-Disposition: form-data; name="descr" 


-----------------------------27368237179714 
Content-Disposition: form-data; name="pprotect" 


-----------------------------27368237179714-- 

在這裏我們可以看到參數,標題,內容類型和信息塊(1 - 文件名和類型, 2 - 文件內容,3 - 附加參數 - 描述和密碼,不一定適用)。 所以我創建了一個模擬這樣的行爲一步一步的類:對網址的HttpWebRequest,申請需要的參數請求,形成與StringBuilder的請求字符串,並將它們轉換爲字節數組,使用FileStream讀取文件,把所有這些東西到MemoryStream,然後寫它請求(從CodeProject上的文章的主要部分代碼,它將文件上傳到Rapidshare主機)。 整潔,但...它似乎並沒有工作:(因爲它返回初始上傳頁面,而不是結果頁面的鏈接,我可以解析並呈現給用戶... 這裏是主要的方法一類上傳:

// Step 1 - request creation 
private HttpWebRequest GetWebrequest(string boundary) 
{ 
      Uri uri = new Uri("http://filehoster.awardspace.com/index.php?do=verify"); 
      System.Net.HttpWebRequest httpWebRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(uri); 
      httpWebRequest.CookieContainer = _cookies; 
      httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary; 
      httpWebRequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.2; ru; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8 (.NET CLR 4.0.20506)"; 
      httpWebRequest.Referer = "http://filehoster.awardspace.com/index.php"; 
      httpWebRequest.Method = "POST"; 
      httpWebRequest.KeepAlive = true; 
      httpWebRequest.Timeout = -1; 
      //httpWebRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; 
      httpWebRequest.Headers.Add("Accept-Charset", "windows-1251,utf-8;q=0.7,*;q=0.7"); 
      httpWebRequest.Headers.Add("Accept-Encoding", "gzip,deflate"); 
      httpWebRequest.Headers.Add("Accept-Language", "ru,en-us;q=0.7,en;q=0.3"); 
      //httpWebRequest.AllowAutoRedirect = true; 
      //httpWebRequest.ProtocolVersion = new Version(1,1); 
      //httpWebRequest.SendChunked = true; 
      //httpWebRequest.Headers.Add("Cache-Control", "no-cache"); 
      //httpWebRequest.ServicePoint.Expect100Continue = false; 
      return httpWebRequest; 
} 
// Step 2 - first message part (before file contents) 
private string GetRequestMessage(string boundary, string FName, string description, string password) 
{  
      System.Text.StringBuilder stringBuilder = new StringBuilder(); 
      stringBuilder.Append("--"); 
      stringBuilder.Append(boundary); 
      stringBuilder.Append("\r\n"); 
      stringBuilder.Append("Content-Disposition: form-data; name=\""); 
      stringBuilder.Append("upfile"); 
      stringBuilder.Append("\"; filename=\""); 
      stringBuilder.Append(FName); 
      stringBuilder.Append("\""); 
      stringBuilder.Append("\r\n"); 
      stringBuilder.Append("Content-Type: application/octet-stream"); 
      stringBuilder.Append("\r\n"); 
      return stringBuilder.ToString(); 
} 
// Step 4 - additional request parameters. Step 3 - reading file is in method below 
private string GetRequestMessageEnd(string boundary) 
{  
      System.Text.StringBuilder stringBuilder = new StringBuilder(); 
      stringBuilder.Append(boundary); 
      stringBuilder.Append("\r\n"); 
      stringBuilder.Append("Content-Disposition: form-data; name=\"descr\""); 
      stringBuilder.Append("\r\n"); 
      stringBuilder.Append("\r\n"); 
      stringBuilder.Append("Default description"); 
      stringBuilder.Append("\r\n"); 
      stringBuilder.Append(boundary); 
      stringBuilder.Append("\r\n"); 
      stringBuilder.Append("Content-Disposition: form-data; name=\"pprotect\""); 
      stringBuilder.Append("\r\n"); 
      stringBuilder.Append("\r\n"); 
      stringBuilder.Append(""); 
      stringBuilder.Append("\r\n"); 
      stringBuilder.Append(boundary); 
      stringBuilder.Append("--"); 
      //stringBuilder.Append("\r\n"); 
      //stringBuilder.Append(boundary); 
      //stringBuilder.Append("\r\n"); 
      return stringBuilder.ToString(); 
} 
// Main method 
public string ProcessUpload(string FilePath, string description, string password) 
{ 
      // Chosen file information 
      FileSystemInfo _file = new FileInfo(FilePath); 
      // Random boundary generation 
      DateTime dateTime2 = DateTime.Now; 
      long l2 = dateTime2.Ticks; 
      string _generatedBoundary = "----------" + l2.ToString("x"); 
      // Web request creation 
      System.Net.HttpWebRequest httpWebRequest = GetWebrequest(_generatedBoundary); 
      // Main app block - form and send request 
      using (System.IO.FileStream fileStream = new FileStream(_file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)) 
      { 
       byte[] bArr1 = Encoding.ASCII.GetBytes("\r\n--" + _generatedBoundary + "\r\n"); 
       // Generating pre-content post message 
       string firstPostMessagePart = GetRequestMessage(_generatedBoundary, _file.Name, description, password); 
       // Writing first part of request 
       byte[] bArr2 = Encoding.UTF8.GetBytes(firstPostMessagePart); 
       Stream memStream = new MemoryStream(); 
       memStream.Write(bArr1, 0, bArr1.Length); 
       memStream.Write(bArr2, 0, bArr2.Length); 
       // Writing file 
       byte[] buffer = new byte[1024]; 
       int bytesRead = 0; 
       while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) 
       { 
        memStream.Write(buffer, 0, bytesRead); 
       } 
       // Generating end of a post message 
       string secondPostMessagePart = GetRequestMessageEnd(_generatedBoundary); 
       byte[] bArr3 = Encoding.UTF8.GetBytes(secondPostMessagePart); 
       memStream.Write(bArr3, 0, bArr3.Length); 
       // Preparing to send 
       httpWebRequest.ContentLength = memStream.Length; 
       fileStream.Close(); 

       Stream requestStream = httpWebRequest.GetRequestStream(); 

       memStream.Position = 0; 
       byte[] tempBuffer = new byte[memStream.Length]; 
       memStream.Read(tempBuffer, 0, tempBuffer.Length); 
       memStream.Close(); 
       // Sending request 
       requestStream.Write(tempBuffer, 0, tempBuffer.Length); 
       requestStream.Close(); 
      } 
      // Delay (?) 
      System.Threading.Thread.Sleep(5000); 
      // Getting response 
      string strResponse = ""; 
      using (Stream stream = httpWebRequest.GetResponse().GetResponseStream()) 
      using (StreamReader streamReader = new StreamReader(stream/*, Encoding.GetEncoding(1251)*/)) 
      { 
       strResponse = streamReader.ReadToEnd(); 
      } 
      return strResponse; 
} 

玩弄ProtocolVersion(1.0,1.1),AllowAutoRedirect(真/假),即使知道ServicePoint.Expect100Continue(假)並沒有得到響應之前,即使是5秒超時解決的問題(內容類型「octet-stream」被選擇用於上傳任何文件(可以使用一些開關用於最流行的jpg/zip/rar/doc等等,但這似乎是普遍的)。邊界是從計時器滴答隨機產生的,沒有什麼大不了的別的呢? :/ 我可以放棄並忘記這一點,但我覺得我很接近解決和然後忘掉它:P。 如果您需要在整個應用程序運行和調試 - 這裏是(70KB,壓縮C#2.0 VS2k8解決方案,無廣告,無病毒):

@Mediafire @FileQube @FileDropper

+0

你是什麼意思「顯示主機的主頁」?你能詳細說明你得到的實際錯誤嗎?什麼不工作? – fretje 2009-06-29 23:05:41

+0

帶有「選擇文件」框並上傳按鈕的頁面: http://i.piccy.info/i3/74/b5/3089a82aa091a0d975b987f1bedd.png 不是包含指向文件鏈接的頁面: http://i.piccy .info/i3/30/48/b66db6dee2e353949bd5d5269557.png 我認爲在發送數據並獲得結果的步驟中不起作用。即使使用AllowAutoRedirect param = true並初始化CookieContainer,重定向也不會發生。 – Jaded 2009-06-30 08:24:45

回答

8

更新:不,不存在重定向。

screenshot

閱讀RFC2388幾次,重寫了代碼,它終於摸索(我猜的麻煩是UTF-讀尾部邊界,而不是正確的7位ASCII)。萬歲? 。都能跟得上:(只小文件轉移,大的拋出「連接被意外關閉」

System.Net.WebException was unhandled by user code 
    Message="The underlying connection was closed: The connection was closed unexpectedly." 
    Source="Uploader" 
    StackTrace: 
    at Uploader.Upload.ProcessUpload(String FilePath, String description, String password) in F:\MyDocuments\Visual Studio 2008\Projects\Uploader\Uploader.cs:line 96 
    at Uploader.Form1.backgroundWorker1_DoWork(Object sender, DoWorkEventArgs e) in F:\MyDocuments\Visual Studio 2008\Projects\Uploader\Form1.cs:line 45 
    at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument) 

我知道這是使用.NET堆棧和幾個解決方案存在錯誤:

1)同時增加的請求

2)超時而ReadWriteTimeout分配request.KeepAlive =假和System.Net.ServicePointManager.Expect100Continue =假

3)設置ProtocolVersion〜1.0 但其中沒有一個也不所有的他們對我的情況完全有幫助。有任何想法嗎?

編輯 - 源代碼:

// .. request created, required params applied 
httpWebRequest.ProtocolVersion = HttpVersion.Version10; // fix 1 
httpWebRequest.KeepAlive = false; // fix 2 
httpWebRequest.Timeout = 1000000000; // fix 3 
httpWebRequest.ReadWriteTimeout = 1000000000; // fix 4 
// .. request processed, data written to request stream 
string strResponse = "";    
try 
{ 
    using (WebResponse httpResponse = httpWebRequest.GetResponse()) // error here 
     { 
      using (Stream responseStream = httpResponse.GetResponseStream()) 
      { 
       using (StreamReader streamReader = new StreamReader(responseStream)) 
        { 
         strResponse = streamReader.ReadToEnd(); 
        } 
       } 
      } 
     } 
catch (WebException exception) 
{ 
    throw exception; 
} 
0

「作爲結果返回初始上傳頁面,而不是帶有鏈接的結果頁面,我可以解析並呈現給用戶......「

也許這只是上傳功能的行爲:在上傳完成後,您可以上傳另一個文件? 我想你必須調用另一個「瀏覽文件」頁面的網址(我想這是你需要的)。


編輯:其實,如果服務器發送一個「重定向」(HTTP 3XX),這件事情,瀏覽器必須處理,所以如果你有自己的客戶端應用程序在瀏覽器代替工作,你必須自己實現重定向。這裏的rfc瞭解更多信息。

+0

事實是在那裏......服務的常見使用場景如下: 1)加載服務首頁somehost.com(實際上是somehost.com/index.php); 2)選擇要通過瀏覽和文件打開對話框上傳的文件; 3)檢查「同意服務條款」複選框啓用上傳按鈕(在非瀏覽器的情況下,它不會影響我猜的任何東西?) 4)點擊「上傳!」 5)等待文件上傳到同一位置(只是在窗體上顯示一些js進度條,忽略) 6)查看並複製指向文件和「刪除文件」操作的鏈接。地址是somehost.com/upload.php?do=verify。 – Jaded 2009-06-30 08:50:56

0

嘗試設置在Web.config中httpRuntime元素的maxRequestLength屬性。

0

在我的情況下,導致該問題的重複文件名也是如此。我將文件的設置保存在xml文件中,但名稱設置相互重複。

 <field name="StillImage"> 
     <prefix>isp_main_</prefix> 
     <suffix>308</suffix> 
     <width>1080</width> 
     <height>1080</height> 
     </field> 
     <field name="ThumbnailImage"> 
     <prefix>isp_thumb_</prefix> // pay attention to this 
     <suffix>308</suffix> 
     <width>506</width> 
     <height>506</height> 
     </field> 
     <field name="Logo"> 
     <prefix>isp_thumb_</prefix> // and this 
     <suffix>306</suffix> 
     <width>506</width> 
     <height>506</height> 
     </field> 

而且,在我另一種情況下,這個問題是在文件長度。請檢查您的服務器上允許的文件大小。在你的腳本只是做檢查這一部分:

dataStream.Write(filesBytesArray, 0, filesBytesArray.Length); 
dataStream.Close(); 

如果你不知道,只是限制在你的前端部分,即上傳的文件大小。 HTML <input type="file">上傳元素,這是good reference for limiting file size and other filter

相關問題