使用 Response.AppendHeader("Content-Disposition", "attachment; filename=...") 時,中文檔名在不同瀏覽器/編碼下易產生亂碼。本文提供兩種徹底解決方案。
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition", "attachment; filename=\"報表.pdf\"");
Response.BinaryWrite(fileBytes);
Response.End();
// 結果:IE 可能顯示「報表.pdf」,Chrome/Firefox 顯示亂碼或截斷
string fileName = "報表.pdf";
string encodedName = Server.UrlEncode(fileName); // %E5%A0%B1%E8%A1%A8.pdf
Response.AppendHeader("Content-Disposition", $"attachment; filename=\"{encodedName}\"");
// 瀏覽器下載時自動解碼為「報表.pdf」
+ 而非 %20,部分瀏覽器解碼異常。filename*=UTF-8''encoded 格式。原理:瀏覽器從請求 URL 最後一段路徑推斷預設檔名。
// 原下載頁面:Download.aspx?id=123
// 改為:Download.aspx/報表.pdf?id=123
// 路由設定 (ASP.NET 4.0+ Routing / MVC / Core 內建支援)
// WebForms 需在 Global.asax 註冊路由
routes.MapPageRoute("Download", "Download/{fileName}", "~/Download.aspx");
// Download.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
string id = Request.QueryString["id"]; // 或 RouteData.Values["id"]
string fileName = GetFileNameFromDb(id); // "報表.pdf"
byte[] bytes = GetFileBytes(id);
Response.Clear();
Response.ContentType = "application/pdf";
// 不需 AppendHeader filename,瀏覽器自動取 URL 最後段 "報表.pdf"
Response.BinaryWrite(bytes);
Response.End();
}
/ \ : * ? " < > | 等非法路徑字元,需預先替換或移除。runAllManagedModulesForAllRequests="true" (IIS 7+) 或 Wildcard Mapping (IIS 6)。string safeName = Regex.Replace(fileName, @"[\\/:*?""<>|]", "_"); // 淨化
string encoded = Server.UrlEncode(safeName);
Response.AppendHeader("Content-Disposition", $"attachment; filename=\"{encoded}\"; filename*=UTF-8''{encoded}");
// 同時支援舊式 filename 與 RFC 5987 filename*
結合路由友善 URL + 雙重 Header,達成跨瀏覽器、跨版本、符合標準的完美下載體驗。