一 介紹
斷點續傳搜索大部分都是下載的斷點續傳,涉及到HTTP協議1.1的Range和Content-Range頭。
來個簡單的介紹
所謂斷點續傳,也就是要從文件已經下載的地方開始繼續下載。在以前版本的 HTTP 協議是不支持斷點的,HTTP/1.1 開始就支持了。一般斷點下載時才用到 Range 和 Content-Range 實體頭。
Range
用於請求頭中,指定第一個字節的位置和最后一個字節的位置,一般格式:
Range:(unit=first byte pos)-[last byte pos]
Content-Range
用於響應頭,指定整個實體中的一部分的插入位置,他也指示了整個實體的長度。在服務器向客戶返回一個部分響應,它必須描述響應覆蓋的范圍和整個實體長度。一般格式:
Content-Range: bytes (unit first byte pos) – [last byte pos]/[entity legth]
請求下載整個文件:
- GET /test.rar HTTP/1.1
- Connection: close
- Host: 116.1.219.219
- Range: bytes=0-801 //一般請求下載整個文件是bytes=0- 或不用這個頭
一般正常回應
- HTTP/1.1 200 OK
- Content-Length: 801
- Content-Type: application/octet-stream
- Content-Range: bytes 0-800/801 //801:文件總大小
而今天要說的是上傳的斷點續傳,用到了Content-Range頭
上傳的續傳原理跟下載的續傳同理。
就是在上傳前把文件拆分后上傳。服務器端接收合並,即使上傳斷了。下次上傳依然從服務器端的文件現有字節后合並文件。最終上傳完成。
二 實現
服務器端
服務端是webapi實現。或是mvc,webform皆可。
服務端的原理就是接收上傳數據流。保存文件。如果此文件已存在。就是合並現有文件。
這里文件的文件名是采用客戶端傳過來的數據。
文件名稱是文件的MD5,保證文件的唯一性。
[HttpGet] public HttpResponseMessage GetResumFile() { //用於獲取當前文件是否是續傳。和續傳的字節數開始點。 var md5str = HttpContext.Current.Request.QueryString["md5str"]; var saveFilePath = HttpContext.Current.Server.MapPath("~/Images/") + md5str; if(System.IO.File.Exists(saveFilePath)) { var fs = System.IO.File.OpenWrite(saveFilePath); var fslength = fs.Length.ToString(); fs.Close(); return new HttpResponseMessage { Content = new StringContent(fslength, System.Text.Encoding.UTF8, "text/plain") }; } return new HttpResponseMessage(HttpStatusCode.OK); } [HttpPost] public HttpResponseMessage Rsume() { var file = HttpContext.Current.Request.InputStream; var filename = HttpContext.Current.Request.QueryString["filename"]; this.SaveAs(HttpContext.Current.Server.MapPath("~/Images/") + filename, file); HttpContext.Current.Response.StatusCode = 200; // For compatibility with IE's "done" event we need to return a result as well as setting the context.response return new HttpResponseMessage(HttpStatusCode.OK); } private void SaveAs(string saveFilePath,System.IO.Stream stream) { long lStartPos = 0; int startPosition = 0; int endPosition = 0; var contentRange = HttpContext.Current.Request.Headers["Content-Range"]; //bytes 10000-19999/1157632 if (!string.IsNullOrEmpty(contentRange)) { contentRange = contentRange.Replace("bytes", "").Trim(); contentRange = contentRange.Substring(0, contentRange.IndexOf("/")); string[] ranges = contentRange.Split('-'); startPosition = int.Parse(ranges[0]); endPosition = int.Parse(ranges[1]); } System.IO.FileStream fs; if (System.IO.File.Exists(saveFilePath)) { fs = System.IO.File.OpenWrite(saveFilePath); lStartPos = fs.Length; } else { fs = new System.IO.FileStream(saveFilePath, System.IO.FileMode.Create); lStartPos = 0; } if (lStartPos > endPosition


