首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

ASP.NET 將二進制流轉為文件下載的正確姿勢

     編輯:程式設計綜合問答

常見誤區

原代碼直接讀取文件到 byte 數組再 Response.BinaryWrite,存在以下問題:

  • 大文件會導致內存溢出(一次性讀入全部內容)。
  • 未設置 Content-Length,進度條無法顯示。
  • Response.End() 會拋出 ThreadAbortException,影響性能。

推薦做法:使用 FileResult / PhysicalFileResult (ASP.NET Core) 或傳輸流

ASP.NET Core (推薦)

public IActionResult Download(string fileName) {
    var path = Path.Combine(_env.ContentRootPath, "Files", fileName);
    if (!System.IO.File.Exists(path)) return NotFound();
    return PhysicalFile(path, "application/octet-stream", fileName);
}

ASP.NET Framework (MVC 5 / WebForms)

public ActionResult Download(string fileName) {
    string path = Server.MapPath("~/Files/" + fileName);
    if (!System.IO.File.Exists(path)) return HttpNotFound();
    
    // 設置響應頭
    Response.Clear();
    Response.ContentType = "application/octet-stream";
    Response.AddHeader("Content-Disposition", 
        "attachment; filename=" + Server.UrlEncode(fileName));
    Response.AddHeader("Content-Length", new FileInfo(path).Length.ToString());
    
    // 分塊傳輸,避免大文件內存壓力
    const int bufferSize = 1024 * 1024; // 1MB
    byte[] buffer = new byte[bufferSize];
    using (var fs = System.IO.File.OpenRead(path)) {
        int bytesRead;
        while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0) {
            Response.OutputStream.Write(buffer, 0, bytesRead);
            Response.Flush(); // 及時發送給客戶端
        }
    }
    Response.SuppressContent = true; // 防止後續內容污染
    HttpContext.ApplicationInstance.CompleteRequest(); // 替代 Response.End()
    return new EmptyResult();
}

WebForms 純 .aspx 頁面

protected void Page_Load(object sender, EventArgs e) {
    string fileName = Request.QueryString["f"];
    if (string.IsNullOrEmpty(fileName)) return;
    string path = Server.MapPath("~/Files/" + fileName);
    if (!File.Exists(path)) { Response.StatusCode = 404; return; }

    Response.Clear();
    Response.ContentType = "application/octet-stream";
    Response.AddHeader("Content-Disposition", 
        "attachment; filename=" + Server.UrlEncode(fileName));
    Response.AddHeader("Content-Length", new FileInfo(path).Length.ToString());
    Response.TransmitFile(path); // 內部使用分塊傳輸,最高效
    Response.SuppressContent = true;
    HttpContext.Current.ApplicationInstance.CompleteRequest();
}

關鍵點總結

  1. 分塊讀寫:使用 Response.TransmitFile 或手動循環 Read/Write,避免大文件佔用內存。
  2. 設置 Content-Length:支持下載進度條與恢復斷點。
  3. 文件名編碼:Server.UrlEncode 處理中文文件名,防止亂碼。
  4. 避免 Response.End():改用 CompleteRequest() 或 SuppressContent,防止線程中止異常。
  5. 異步支持:ASP.NET Core 原生異步,Framework 可用 Task 包裝提升併發。

安全提示

  • 嚴格驗證 fileName,防止目錄遍歷攻擊(../)。
  • 使用白名單或數據庫映射 ID 到物理路徑,不直接暴露路徑參數。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved