對 Response 回傳結果適時的使用快取機制,可以有助於效能提升,避免重複的運算浪費。
本篇將介紹 ASP.NET Core 如何設定 Response 的 Client 端暫存及Server 端快取。
iT 邦幫忙 2018 鐵人賽 - Modern Web 組參賽文章:
[Day28] ASP.NET Core 2 系列 - Response 快取
ASP.NET Core 對於網頁的 Response 快取有分兩種:
- Client 端暫存
- Server 端快取
ASP.NET Core 可以透過 [ResponseCache]
設定 Response 的暫存方式。並套用到要使用 Response 快取的 Controller 或 Action。
Client 端暫存
透過 HTTP Header 的 Cache-Control
告知瀏覽器,把頁面存在瀏覽器暫存區。如下圖:
Client 端暫存只要套用 [ResponseCache]
即可,不需要多註冊額外的服務,如下:
Controllers\HomeController.cs
1 | public class HomeController : Controller |
[ResponseCache]
可以設定的參數如下:
Duration
設定快取有效時間(單位是秒)。Location
設定快取方式,有三種選項:ResponseCacheLocation.Any
可與不同使用者共用的暫存。
HTTP Header 會設定成Cache-Control: public
。ResponseCacheLocation.Client
不可共用的暫存,以使用者區分 (如:依照 Cookies 區分)。
HTTP Header 會設定成Cache-Control: private
。ResponseCacheLocation.None
不使用暫存功能。
HTTP Header 會設定成Cache-Control: no-cache
。
NoStore
告知瀏覽器,不要把 Response 結果存起來。
HTTP Header 會設定成Cache-Control: no-store
。VaryByHeader
設定暫存依照設定的 HTTP Header 區分。
例如:VaryByHeader="Cookie"
。
雖然是同一台電腦連上同一個 URL,但因為 Cookie 不同,所以 Response 暫存的內容也會有所不同。VaryByQueryKeys
設定暫存依照設定的 URL Query String 區分。
例如:VaryByQueryKeys = new string[] { "q" }
。http://localhost:5000/?q=123
及http://localhost:5000/?q=456
雖然是連上同一個 URL,但因為設定的 URL Query String 的q
不同,所以 Response 暫存的內容也會有所不同。CacheProfileName
可以在 MVC Service 設定 CacheProfile,然透套用到多個地方如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.CacheProfiles.Add("Default",
new CacheProfile()
{
Duration = 60,
Location = ResponseCacheLocation.Client
});
});
}
// Controllers\HomeController.cs
public class HomeController : Controller
{
[ ]
public IActionResult Index()
{
return View();
}
}
Server 端快取
Server 端 Response 快取需要
Microsoft.AspNetCore.ResponseCaching
套件。
ASP.NET Core 2.0 以上版本,預設是參考Microsoft.AspNetCore.All
,已經包含Microsoft.AspNetCore.ResponseCaching
,所以不用再安裝。
Server 端 Response 快取功能是在 ASP.NET Core 1.1 之後的版本才有,如果是 ASP.NET Core 2.0 以前版本,可以透過 .NET Core CLI 在專案資料夾執行安裝指令:
1 | dotnet add package Microsoft.AspNetCore.ResponseCaching |
Server 端 Response 快取適合用在常被呼叫的頁面或 API,且資料是 可共用的資料 ,也就是所有網頁使用者看到的資料都一樣。當請求相同頁面時,會把上次的處理結果從 Server 的快取回傳給 Client,省去後續一連串的行為。如下圖:
- 第一次呼叫 Action 時,會經過重重運算,甚至連到資料庫取值等等。
- 第二次呼叫 Action 時,由於上次回傳結果已經存在 Server 快取,因此就直接從快取回傳上次的結果,省去其他運算步驟。
如果要搭配 Server 端 Response 快取,除了套用 [ResponseCache]
外,還需要在 DI 容器注入 ResponseCaching 服務及註冊 ResponseCaching 的 Middleware,如下:
Startup.cs
1 | using Microsoft.AspNetCore.Builder; |
Server 快取可以設定的參數如下:
UseCaseSensitivePaths
URL 是否區分大小寫為不同的 Response 快取。
(預設為 true)MaximumBodySize
單個 Response 快取的大小限制(單位是 Bytes)。
(預設為 64 MB)SizeLimit
Response 快取的總大小限制(單位是 Bytes)。
(預設為 100 MB)
建立一個簡單的範例:
Controllers\HomeController.cs
1 | public class HomeController : Controller |
Views\Home\Index.cshtml
1 | @model string |
執行結果:
第一次連入 http://localhost:5000/
時,就被放入 Server 快取中,後續的 Request 全部都是從 Server 快取回應,所以不會進到 Action,自然不會有 Action 中的 Log 資訊。
Server 快取條件
嘗試在瀏覽器一直按 F5
刷新頁面,會發現根本不從 Server 快取拿結果,而是每次都重新跟 Action 拿新資料。這是正常的行為,因為要使用 Server 快取有條件的限制。
要使用 Server 快取,必須要達成以下條件:
- 回傳的狀態必須是 HTTP Status 200 (OK)。
- Request 的 HTTP Methods 必須是
GET
或HEAD
。 - 不能有其他的 Middleware 在加工 ResponseCachingMiddleware 之前異動 Response。
- HTTP Header 不能用
Authorization
。 - HTTP Header 的
Cache-Control
值必須是public
。
(F5
刷新頁面不會帶Cache-Control
,所以使用 Server 快取條件不成立) - HTTP Header 不能用
Set-Cookie
。 - HTTP Header 的
Vary
值不能為*
。 - 不能使用
IHttpSendFileFeature
。 - 不能設定
no-store
。 - 單一回傳快取不能大於
MaximumBodySize
。 - 總體快取不能大於
SizeLimit
。
如果用過 ASP.NET 的
[OutputCache]
,千萬不要以為[ResponseCache]
跟它是一樣的東西。[ResponseCache]
多了上面一連串的必備條件…
(我也為此卡了一陣子,還把 Source Code Checkout 下來 Debug…)