首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

ASP.NET 與 ASP 隱藏檔案下載真實路徑的完整實作

     編輯:關於C語言

核心原則

絕不在 URL 直接暴露實體檔案路徑。改由資料庫儲存檔案相對路徑或 ID,下載頁面根據 ID 查詢路徑,再以 Response.BinaryWrite 或 Response.WriteFile 串流輸出。

一、ASP.NET (C#) 實作

// Download.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
    string fileId = Request.QueryString["id"];
    if (string.IsNullOrEmpty(fileId)) { Response.End(); return; }

    // 1. 從資料庫取得相對路徑
    string sql = "SELECT FileVirtualPath FROM Attachments WHERE FileID = @id";
    string relPath = DbHelper.ExecuteScalar(sql, new SqlParameter("@id", fileId))?.ToString();
    if (string.IsNullOrEmpty(relPath)) { Response.Write("檔案不存在"); Response.End(); return; }

    // 2. 轉換為實體路徑
    string fullPath = Server.MapPath(relPath);
    if (!File.Exists(fullPath)) { Response.Write("實體檔案遺失"); Response.End(); return; }

    // 3. 設定回應標頭
    FileInfo fi = new FileInfo(fullPath);
    Response.Clear();
    Response.ClearHeaders();
    Response.Buffer = false; // 大檔案建議 false,避免記憶體暴增
    Response.ContentType = "application/octet-stream";
    Response.AddHeader("Content-Disposition", 
        $"attachment; filename=\"{HttpUtility.UrlEncode(fi.Name, Encoding.UTF8)}\"");
    Response.AddHeader("Content-Length", fi.Length.ToString());

    // 4. 串流輸出
    Response.WriteFile(fullPath);
    Response.Flush();
    Response.End();
}

二、傳統 ASP (VBScript) 實作

<!--#include file="conn.asp" -->
<%
Response.Buffer = True
Response.Clear

Dim id, sql, rs, relPath, fullPath, fso, file, fileName, fileSize
id = Trim(Request.QueryString("id"))
If id = "" Then Response.Write("參數錯誤") : Response.End

sql = "SELECT FilePath FROM Attachments WHERE FileID = " & id
Set rs = Server.CreateObject("ADODB.Recordset")
rs.Open sql, conn, 1, 1
If rs.EOF Then Response.Write("找不到記錄") : Response.End
relPath = rs("FilePath")
rs.Close : Set rs = Nothing

fullPath = Server.MapPath(relPath)
Set fso = Server.CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(fullPath) Then Response.Write("檔案不存在") : Response.End
Set file = fso.GetFile(fullPath)
fileName = file.Name
fileSize = file.Size
Set file = Nothing : Set fso = Nothing

' 依副檔名決定 ContentType
Dim ext, contentType
ext = LCase(Right(fileName, 4))
Select Case ext
    Case ".pdf"  : contentType = "application/pdf"
    Case ".doc"  : contentType = "application/msword"
    Case ".xls"  : contentType = "application/vnd.ms-excel"
    Case ".jpg", "jpeg" : contentType = "image/jpeg"
    Case ".png"  : contentType = "image/png"
    Case ".zip"  : contentType = "application/zip"
    Case Else    : contentType = "application/octet-stream"
End Select

Response.AddHeader "Content-Disposition", "attachment; filename=" & fileName
Response.AddHeader "Content-Length", fileSize
Response.ContentType = contentType
Response.Charset = "UTF-8"

' 使用 ADODB.Stream 讀取二進位輸出(支援大檔案)
Dim stream
Set stream = Server.CreateObject("ADODB.Stream")
stream.Open
stream.Type = 1 ' adTypeBinary
stream.LoadFromFile fullPath
Response.BinaryWrite stream.Read
stream.Close
Set stream = Nothing
Response.Flush
Response.End
%>

關鍵安全性檢查清單

  • SQL 參數化:防止注入攻擊(C# 使用 SqlParameter,ASP 確保 ID 為數字)。
  • 路徑遍歷防護:資料庫僅存相對路徑,Server.MapPath 限制在網站根目錄下。
  • 檔名編碼:HttpUtility.UrlEncode(Encoding.UTF8) 解決中文檔名下載亂碼。
  • 大檔案支援:Response.Buffer = false + Response.WriteFile / ADODB.Stream 避免記憶體爆炸。
  • 權限控管:下載前驗證使用者登入狀態與檔案存取權限。

進階:支援斷點續傳 (Range Requests)

需解析 Request.Headers["Range"],回傳 206 Partial Content、Content-Range、Accept-Ranges: bytes。建議使用成熟庫(如 FileResult 擴充或 RangeFileStreamResult)而非手寫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved