為何要多伺服器儲存
Web前端最佳化其中有一個規則就是通過不同的主機並行下載資源(Parallelize downloads across hostnames),IE瀏覽器對同一個網域名稱的檔案,同時只能下載2個檔案,這樣的話,假設同一個頁面站內資源很多,尤其是圖片資源過多時,頁面載入速度將會受到影響,這時分散式處理檔案顯得尤為重要,中大型網站往往通過多個資原始伺服器來儲存這些檔案,比如部落格園本身也是將圖片檔案儲存在imgn.cnblogs.com的伺服器上。更大型的網站可能會將一些js、css檔案也會從主域中分離處理。
跨伺服器上傳解決方案
跨伺服器上傳其實就是在a站上傳檔案儲存到b站,比較常見的兩種方式如下。
第一種是非常靈活的方式,假設A.com和B.com,在A上有一個檔案gate.aspx,這個頁面無參數時跳轉到B上的upload.aspx,其實上傳是通過B上的upload.aspx上傳到B伺服器,然後上傳成功後將上傳結果以參數方式再傳遞給gate.aspx;gate.aspx接收到這個參數再做相應的處理。這種方式實質上並不涉及到跨伺服器,僅僅是利用一些靈活的變通方式。
第二種方式就是我們今天要提到的實實在在的跨伺服器上傳,利用B.com的handler檔案,先將檔案進行編碼,使用POST方式傳遞到handler,然後handler將檔案儲存到伺服器上,同時返回相應的結果。
將檔案轉為Base64:
string fileName = FileUpload.FileName;FileInfo file = new FileInfo(fileName);string ext=file.Extension;Stream stream = FileUpload.PostedFile.InputStream;BinaryReader br = new BinaryReader(stream);byte[] fileByte = br.ReadBytes((int)stream.Length);string baseFileString = Convert.ToBase64String(fileByte);
在handler.ashx中做處理:
/// <summary> /// 上傳圖片 /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class CrossServerFileUpload : IHttpHandler { private string _allowFileTypes = "gif,jpg,jpeg,png,bmp"; private HttpContext _context; public void ProcessRequest(HttpContext context) { _context = context; string src = context.Request.Form["src"];if (string.IsNullOrEmpty(src)) return;src = src.ToLower(); bool isExtValid = src.EndsWith(".jpg") || src.EndsWith(".png") || src.EndsWith(".gif") || src.EndsWith(".bmp") || src.EndsWith(".jpeg"); if (isExtValid) { context.Response.ContentType = "text/plain"; string ext = context.Request.Form["ext"]; string content = context.Request.Form["data"]; Upload(ext, content); } } /// <summary> /// 上傳類 /// </summary> /// <param name="ext"></param> /// <param name="content"></param> private void Upload(string ext,string content) { if (string.IsNullOrEmpty(ext) || string.IsNullOrEmpty(content)) { return; } //儲存圖片 string dateNum = DateTime.Now.ToString("yyyyMM");//按月存放 string fileName = Guid.NewGuid() + ext; string currentPath = HttpContext.Current.Request.PhysicalApplicationPath + "upload\\" + dateNum + "\\"; string fullPath =currentPath + fileName; if (!Directory.Exists(currentPath)) Directory.CreateDirectory(currentPath); byte[] buffer = Convert.FromBase64String(content); using (FileStream fileStream = new FileStream(fullPath, FileMode.Create)) { fileStream.Write(buffer, 0, buffer.Length); } string host = _context.Request.Url.Host; ResponseWrite(string.Format("http://" + host + "/upload/{0}/{1}", dateNum, fileName));//返回圖片儲存路徑 } /// <summary> /// 產生http內容 /// </summary> /// <param name="content"></param> private void ResponseWrite(string content) { _context.Response.ClearContent(); _context.Response.ContentType = "text/plain"; _context.Response.Write(content); _context.Response.End(); }
以上是跨伺服器處理代碼的核心代碼,實際應用中還需要考慮許可權問題。
代碼下載