ASP.NET 提供 **頁面輸出快取**,將渲染後的 HTML 直接儲存於伺服器記憶體、用戶端瀏覽器或 Proxy 伺服器,後續相同請求可跳過頁面生命週期直接回傳,大幅提升效能。最簡單的方式是在 `.aspx` 頁面頂端加入 `@OutputCache` 指令進行聲明式設定。
<%@ OutputCache Duration="秒數" VaryByParam="參數名稱" [Location="位置"] [VaryByCustom="自訂字串"] [VaryByHeader="Header名稱"] [NoStore="true|false"] [SqlDependency="資料庫相依性"] %>
| 屬性 | 說明 | 範例 |
|---|---|---|
| Duration | 快取持續秒數 (必須 > 0) | `Duration="60"` (快取 60 秒) |
| VaryByParam | 依查詢字串/表單參數變化建立不同快取版本。`*` 表示所有參數;`none` 表示不依參數變化 | `VaryByParam="id"` / `VaryByParam="*"` / `VaryByParam="none"` |
| 屬性 | 說明 | 值/範例 |
|---|---|---|
| Location | 快取儲存位置 (列舉 OutputCacheLocation) | `Any` (預設, 伺服器+用戶端+Proxy) `Client` (僅瀏覽器) `Server` (僅伺服器) `ServerAndClient` (伺服器+瀏覽器) `None` (停用輸出快取) `Any` (預設) |
| VaryByCustom | 自訂快取變異鍵,需在 `Global.asax` 覆寫 `GetVaryByCustomString` | `VaryByCustom="browser"` (內建,依瀏覽器類型/版本) `VaryByCustom="userRole"` (自訂) |
| VaryByHeader | 依 HTTP Header 變化建立不同快取 (如 `Accept-Language`、`User-Agent`) | `VaryByHeader="Accept-Language"` |
| NoStore | `true` 時發送 `Cache-Control: no-store`,防止敏感資料被快取 (Proxy/瀏覽器) | `NoStore="true"` |
| SqlDependency | SQL Server 查詢通知相依性,資料異動時自動使快取失效 | `SqlDependency="CommandNotification"` |
| CacheProfile | 引用 `web.config` 中定義的 ` | `CacheProfile="LongTerm"` |
public enum OutputCacheLocation {
Any, // 伺服器、用戶端、Proxy 皆可快取 (預設)
Client, // 僅用戶端瀏覽器快取 (發送 Cache-Control: private)
Server, // 僅伺服器記憶體快取 (不發送客戶端快取標頭)
ServerAndClient,// 伺服器 + 用戶端
None, // 停用輸出快取 (仍可程式碼控制)
Downstream // 僅 Proxy/下游快取 (罕用)
}
<%@ OutputCache Duration="60" VaryByParam="none" %>
<%@ OutputCache Duration="300" VaryByParam="productId" Location="Server" %>
<%@ OutputCache Duration="600" VaryByParam="id" VaryByHeader="Accept-Language" Location="Server" %>
<%@ OutputCache Duration="120" VaryByParam="*" VaryByCustom="userRole" Location="Server" %>
// Global.asax.cs
public override string GetVaryByCustomString(HttpContext context, string custom) {
if (custom == "userRole") {
// 依使用者角色產生快取鍵
return context.User.IsInRole("Admin") ? "Admin" : "User";
}
return base.GetVaryByCustomString(context, custom);
}
<!-- web.config -->
<system.web>
<outputCacheSettings>
<outputCacheProfiles>
<add name="Default" duration="60" varyByParam="none" location="Server" />
<add name="ProductDetail" duration="300" varyByParam="id" location="Server" />
<add name="UserDashboard" duration="120" varyByParam="*" varyByCustom="userRole" location="Server" />
</outputCacheProfiles>
</outputCacheSettings>
</system.web>
<%@ OutputCache CacheProfile="ProductDetail" %>
聲明式指令無法涵蓋動態邏輯 (如依權限決定是否快取),可在 `Page_Load` 使用 `Response.Cache`:
Response.Cache.SetExpires(DateTime.Now.AddMinutes(10));
Response.Cache.SetCacheability(HttpCacheability.Server); // 或 Public, Private
Response.Cache.VaryByParams["id"] = true;
Response.Cache.SetValidUntilExpires(true); // 忽略用戶端重新整理要求
// 若不想快取:
Response.Cache.SetNoStore();
| 誤區 | 後果 | 正確做法 |
|---|---|---|
| 敏感資料頁面 (帳號、訂單) 未設 `NoStore="true"` 或 `Location="Server"` | Proxy/瀏覽器快取導致資料洩露 (共用電腦風險) | 個人化/敏感頁面:`Location="Server"` + `NoStore="true"` |
| `VaryByParam="*"` 濫用 | 每個查詢字串組合產生獨立快取,記憶體暴增 | 僅列出真正影響輸出的參數 (`id`, `category`) |
| 快取靜態內容 (CSS/JS/圖片) 用 OutputCache | 不必要開銷,IIS 靜態檔案快取/壓縮/ETag 已足夠 | 靜態資源用 ` |
| Postback 頁面啟用 OutputCache | ViewState/事件驗證失效、使用者看到舊資料 | **含表單回發的頁面勿用 OutputCache**,改用資料快取 (`Cache.Insert`) |
| 未設 `VaryByHeader="Accept-Language"` 多語言頁面 | 不同語言使用者看到同一語言快取版本 | 多語言頁面必加 `VaryByHeader="Accept-Language"` |
善用 `@OutputCache` 聲明式快取,能以最少代碼獲得最大效能提升。關鍵在於精確設定 VaryBy* 變異條件、正確選擇 Location、敏感資料必加 NoStore,並定期監控快取命中率與記憶體使用量。