ASP.NET Core 中的回應快取中介軟體
作者:John Luo 與 Rick Anderson
本文說明如何在 ASP.NET Core 應用程式中設定回應快取中介軟體。 中介軟體會判斷回應何時可供快取、儲存回應,以及提供來自快取的回應。 如需 HTTP 快取和 [ResponseCache]
屬性的簡介,請參閱回應快取。
回應快取中介軟體:
- 根據 HTTP 快取標頭啟用快取伺服器回應。 實作標準 HTTP 快取語意。 根據 Proxy 之類的 HTTP 快取標頭快取。
- 通常對 Razor Pages 之類的 UI 應用程式並不適用,因為瀏覽器通常會設定造成無法快取的要求標頭。 輸出快取可在 ASP.NET Core 7.0 和更新版本中取得,對 UI 應用程式有益。 使用輸出快取,設定會決定應該獨立於 HTTP 標頭快取的內容。
- 對於來自符合快取條件用戶端的公用 GET 或 HEAD API 要求可能會有幫助。
若要測試回應快取,請使用 Fiddler 或可明確設定要求標頭的其他工具。 明確設定標頭是測試快取的慣用方式。 如需詳細資訊,請參閱疑難排解。
組態
在 Program.cs
中,將回應快取中介軟體服務 AddResponseCaching 新增至服務集合,並將應用程式設定為搭配 UseResponseCaching 擴充方法使用中介軟體。 UseResponseCaching
將中介軟體新增至要求處理管線:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddResponseCaching();
var app = builder.Build();
app.UseHttpsRedirection();
// UseCors must be called before UseResponseCaching
//app.UseCors();
app.UseResponseCaching();
警告
在使用 CORS 中介軟體之前,必須在 UseResponseCaching 之前先呼叫 UseCors。
範例應用程式會新增標頭來控制後續要求的快取:
- 快取控制:快取最多 10 秒的可快取回應。
- 不同:只有當後續要求的 Accept-Encoding 標頭符合原始要求時,才設定中介軟體來提供快取的回應。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddResponseCaching();
var app = builder.Build();
app.UseHttpsRedirection();
// UseCors must be called before UseResponseCaching
//app.UseCors();
app.UseResponseCaching();
app.Use(async (context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(10)
};
context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] =
new string[] { "Accept-Encoding" };
await next();
});
app.MapGet("/", () => DateTime.Now.Millisecond);
app.Run();
上述標頭不會寫入回應,而且會在控制器、動作或 Razor Page 時被覆寫:
- 具有 [ResponseCache] 屬性。 即使未設定屬性,也是如此。 例如,省略 VaryByHeader 屬性會導致從回應中移除對應的標頭。
回應快取中介軟體只會快取導致 200 (OK) 狀態碼的伺服器回應。 中介軟體會忽略任何其他回應,包括錯誤頁面。
警告
包含已驗證用戶端內容的回應必須標示為不可快取,以防止中介軟體儲存及處理這些回應。 如需中介軟體如何判斷回應是否可快取的詳細資訊,請參閱 快取的條件 。
上述程式碼通常不會將快取的值傳回至瀏覽器。 使用 Fiddler 或其他工具,可明確設定要求標頭,並偏好用於測試快取。 如需詳細資訊,請參閱本文中的疑難排解。
選項。
下表顯示回應快取選項。
選項 | 描述 |
---|---|
MaximumBodySize | 回應主體的最大可快取大小,以位元組為單位。 預設值為 64 * 1024 * 1024 (64 MB)。 |
SizeLimit | 回應快取中介軟體的大小限制,以位元組為單位。 預設值為 100 * 1024 * 1024 (100 MB)。 |
UseCaseSensitivePaths | 判斷回應是否在區分大小寫的路徑上快取。 預設值是 false 。 |
下列範例會將中介軟體設定為:
- 快取主體大小小於或等於 1,024 個位元組的回應。
- 依區分大小寫的路徑儲存回應。 例如,
/page1
和/Page1
會分開儲存。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddResponseCaching(options =>
{
options.MaximumBodySize = 1024;
options.UseCaseSensitivePaths = true;
});
var app = builder.Build();
app.UseHttpsRedirection();
// UseCors must be called before UseResponseCaching
//app.UseCors();
app.UseResponseCaching();
app.Use(async (context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(10)
};
context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] =
new string[] { "Accept-Encoding" };
await next(context);
});
app.MapGet("/", () => DateTime.Now.Millisecond);
app.Run();
VaryByQueryKeys
使用 MVC、Web API 控制器或 Razor Pages 頁面模型時,[ResponseCache]
屬性指定為回應快取設定適當標頭所需的參數。 [ResponseCache]
屬性中唯一嚴格要求中介軟體的參數是 VaryByQueryKeys,它與實際的 HTTP 標頭不對應。 如需詳細資訊,請參閱 ASP.NET Core 中的回應快取。
在不使用 [ResponseCache]
屬性時,回應快取可能會隨著 VaryByQueryKeys
而有所不同。 直接從 HttpCoNtext.Features 使用 ResponseCachingFeature:
var responseCachingFeature = context.HttpContext.Features.Get<IResponseCachingFeature>();
if (responseCachingFeature != null)
{
responseCachingFeature.VaryByQueryKeys = new[] { "MyKey" };
}
在 VaryByQueryKeys
中使用等於 *
的單一值會根據所有請求查詢參數而改變快取。
回應快取中介軟體所使用的 HTTP 標頭
下表提供影響回應快取的 HTTP 標頭相關資訊。
標題 | 詳細資料 |
---|---|
Authorization |
如果標頭存在,則不會快取回應。 |
Cache-Control |
中介軟體只會考慮針對標有 public 快取指示詞的回應進行快取。 使用下列參數控制快取:
max-stale ,中介軟體就不會採取任何動作。‡ proxy-revalidate 的效果與 must-revalidate 相同。如需詳細資訊,請參閱 RFC 9111:要求指示詞。 |
Pragma |
要求中的 Pragma: no-cache 標頭會產生與 Cache-Control: no-cache 相同的效果。 該標頭將被 Cache-Control 標頭中的相關指示詞 (如果存在) 覆寫。 考慮與 HTTP/1.0 的回溯相容性。 |
Set-Cookie |
如果標頭存在,則不會快取回應。 要求處理管道中的中介軟體會設定一組或多組 Cookie,以防從快取回應那邊取得回應快取中介軟體 (例如:cookie 型的 TempData 提供者)。 |
Vary |
標頭 Vary 會用來變更另一個標頭的快取回應。 例如,透過包含 Vary: Accept-Encoding 標頭進行編碼來快取回應,它分別快取具有標頭 Accept-Encoding: gzip 和 Accept-Encoding: text/plain 的要求的回應。 具有 * 標頭值的回應永遠不會儲存。 |
Expires |
除非被其他 Cache-Control 標頭覆寫,否則不會儲存或擷取此標頭視為過時的回應。 |
If-None-Match |
如果值不是 * ,且回應的 ETag 不符合提供的任何值,則會從快取提供完整回應。 否則,會提供 304 (未修改) 的回應。 |
If-Modified-Since |
如果 If-None-Match 標頭不存在,且快取的回應日期比提供的值新,則將從快取提供完整回應。 否則,會提供 304 - 未修改的回應。 |
Date |
當從快取提供服務時,如果原始回應中未提供 Date 標頭,則由中介軟體設定 Date 標頭。 |
Content-Length |
當從快取提供服務時,如果原始回應中未提供 Content-Length 標頭,則由中介軟體設定 Content-Length 標頭。 |
Age |
原始回應中傳送的 Age 標頭會遭忽略。 中介軟體會在提供快取回應時計算新的值。 |
快取會遵守要求 Cache-Control 指示詞
中介軟體遵守 RFC 9111:HTTP 快取規則 (第 5.2 節。快取控制)。 規則需要快取,才能接受用戶端所傳送的有效 Cache-Control
標頭。 在規格下,用戶端可以使用標頭值 no-cache
提出要求,並強制伺服器為每個要求產生新的回應。 目前,使用中介軟體時,沒有任何開發人員控制此快取行為,因為中介軟體遵守官方快取規格。
若要進一步控制快取行為,請探索 ASP.NET Core 的其他快取功能。 請參閱下列主題的說明:
疑難排解
回應快取中介軟體會使用容量有限的 IMemoryCache。 當超出容量時,記憶體快取將被壓縮。
如果快取行為不如預期,請確認回應可進行快取且能夠從快取提供。 檢查要求的傳入標頭和回應的傳出標頭。 啟用記錄以協助偵錯。
測試快取行為並進行疑難排解時,瀏覽器通常會設定防止快取的要求標頭。 例如,瀏覽器可能會在重新整理頁面時,將 Cache-Control
標頭設定為 no-cache
或 max-age=0
。 Fiddler 和其他工具可以明確設定要求標頭,並偏好用於測試快取。
快取的條件
- 要求必須產生具有 200 (OK) 狀態碼的伺服器回應。
- 要求方法必須是 GET 或 HEAD。
- 回應快取中介軟體必須放在需要快取的中介軟體之前。 如需詳細資訊,請參閱 ASP.NET Core 中介軟體。
- 標頭
Authorization
不得存在。 Cache-Control
標頭參數必須為有效,而且回應必須標示public
且未標示private
。- 如果
Cache-Control
標頭不存在,則Pragma: no-cache
標頭不得存在,因為Cache-Control
標頭會覆寫存在的Pragma
標頭。 - 標頭
Set-Cookie
不得存在。 Vary
標頭參數必須有效且不等於*
。Content-Length
標頭值 (如有設定) 必須符合回應主體的大小。- IHttpSendFileFeature 未使用。
- 回應不得過時,如
Expires
標頭和max-age
與s-maxage
快取指示詞所指定。 - 回應緩衝必須成功。 回應的大小必須小於設定或預設 SizeLimit。 回應的主體大小必須小於所設定或預設 MaximumBodySize。
- 根據 RFC 9111:HTTP 快取,回應必須可快取。 例如,
no-store
指示詞不能存在於要求或回應標頭欄位中。 如需詳細資訊,請參閱 RFC 9111:HTTP 快取 (第 3 節:將回應儲存在快取中。
注意
用於產生安全權杖的 Antiforgery 系統可防止跨網站偽造要求 (CSRF) 攻擊將 Cache-Control
和 Pragma
標頭設定為 no-cache
,以便回應不會被快取。 如需如何停用 HTML 表單元素的反偽造權杖資訊,請參閱在 ASP.NET Core 中防止跨網站偽造要求 (XSRF/CSRF) 攻擊。
其他資源
本文說明如何在 ASP.NET Core 應用程式中設定回應快取中介軟體。 中介軟體會判斷回應何時可供快取、儲存回應,以及提供來自快取的回應。 如需 HTTP 快取和 [ResponseCache]
屬性的簡介,請參閱回應快取。
檢視或下載範例程式碼 \(英文\) (如何下載)
組態
回應快取中介軟體可透過共用架構隱含提供給 ASP.NET Core 應用程式。
在 Startup.ConfigureServices
中,將回應快取中介軟體新增至服務集合:
public void ConfigureServices(IServiceCollection services)
{
services.AddResponseCaching();
services.AddRazorPages();
}
將應用程式設定為搭配 UseResponseCaching 擴充方法使用中介軟體,將中介軟體新增至 Startup.Configure
中的要求處理管線:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
// UseCors must be called before UseResponseCaching
// app.UseCors("myAllowSpecificOrigins");
app.UseResponseCaching();
app.Use(async (context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(10)
};
context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] =
new string[] { "Accept-Encoding" };
await next();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
警告
在使用 CORS 中介軟體之前,必須在 UseResponseCaching 之前先呼叫 UseCors。
範例應用程式會新增標頭來控制後續要求的快取:
- 快取控制:快取最多 10 秒的可快取回應。
- 不同:只有當後續要求的 Accept-Encoding 標頭符合原始要求時,才設定中介軟體來提供快取的回應。
// using Microsoft.AspNetCore.Http;
app.Use(async (context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(10)
};
context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] =
new string[] { "Accept-Encoding" };
await next();
});
上述標頭不會寫入回應,而且會在控制器、動作或 Razor Page 時被覆寫:
- 具有 [ResponseCache] 屬性。 即使未設定屬性,也是如此。 例如,省略 VaryByHeader 屬性會導致從回應中移除對應的標頭。
回應快取中介軟體只會快取導致 200 (OK) 狀態碼的伺服器回應。 中介軟體會忽略任何其他回應,包括錯誤頁面。
警告
包含已驗證用戶端內容的回應必須標示為不可快取,以防止中介軟體儲存及處理這些回應。 如需中介軟體如何判斷回應是否可快取的詳細資訊,請參閱 快取的條件 。
選項。
下表顯示回應快取選項。
選項 | 描述 |
---|---|
MaximumBodySize | 回應主體的最大可快取大小,以位元組為單位。 預設值為 64 * 1024 * 1024 (64 MB)。 |
SizeLimit | 回應快取中介軟體的大小限制,以位元組為單位。 預設值為 100 * 1024 * 1024 (100 MB)。 |
UseCaseSensitivePaths | 判斷回應是否在區分大小寫的路徑上快取。 預設值是 false 。 |
下列範例會將中介軟體設定為:
- 快取主體大小小於或等於 1,024 個位元組的回應。
- 依區分大小寫的路徑儲存回應。 例如,
/page1
和/Page1
會分開儲存。
services.AddResponseCaching(options =>
{
options.MaximumBodySize = 1024;
options.UseCaseSensitivePaths = true;
});
VaryByQueryKeys
使用 MVC/Web API 控制器或 Razor Pages 頁面模型時,[ResponseCache]
屬性會指定為設定回應快取適當標頭所需的參數。 [ResponseCache]
屬性中唯一嚴格要求中介軟體的參數是 VaryByQueryKeys,它與實際的 HTTP 標頭不對應。 如需詳細資訊,請參閱 ASP.NET Core 中的回應快取。
在不使用 [ResponseCache]
屬性時,回應快取可能會隨著 VaryByQueryKeys
而有所不同。 直接從 HttpCoNtext.Features 使用 ResponseCachingFeature:
var responseCachingFeature = context.HttpContext.Features.Get<IResponseCachingFeature>();
if (responseCachingFeature != null)
{
responseCachingFeature.VaryByQueryKeys = new[] { "MyKey" };
}
在 VaryByQueryKeys
中使用等於 *
的單一值會根據所有請求查詢參數而改變快取。
回應快取中介軟體所使用的 HTTP 標頭
下表提供影響回應快取的 HTTP 標頭相關資訊。
標題 | 詳細資料 |
---|---|
Authorization |
如果標頭存在,則不會快取回應。 |
Cache-Control |
中介軟體只會考慮針對標有 public 快取指示詞的回應進行快取。 使用下列參數控制快取:
max-stale ,中介軟體就不會採取任何動作。‡ proxy-revalidate 的效果與 must-revalidate 相同。如需詳細資訊,請參閱 RFC 9111:要求指示詞。 |
Pragma |
要求中的 Pragma: no-cache 標頭會產生與 Cache-Control: no-cache 相同的效果。 該標頭將被 Cache-Control 標頭中的相關指示詞 (如果存在) 覆寫。 考慮與 HTTP/1.0 的回溯相容性。 |
Set-Cookie |
如果標頭存在,則不會快取回應。 要求處理管道中的中介軟體會設定一組或多組 Cookie,以防從快取回應那邊取得回應快取中介軟體 (例如:cookie 型的 TempData 提供者)。 |
Vary |
標頭 Vary 會用來變更另一個標頭的快取回應。 例如,透過包含 Vary: Accept-Encoding 標頭進行編碼來快取回應,它分別快取具有標頭 Accept-Encoding: gzip 和 Accept-Encoding: text/plain 的要求的回應。 具有 * 標頭值的回應永遠不會儲存。 |
Expires |
除非被其他 Cache-Control 標頭覆寫,否則不會儲存或擷取此標頭視為過時的回應。 |
If-None-Match |
如果值不是 * ,且回應的 ETag 不符合提供的任何值,則會從快取提供完整回應。 否則,會提供 304 (未修改) 的回應。 |
If-Modified-Since |
如果 If-None-Match 標頭不存在,且快取的回應日期比提供的值新,則將從快取提供完整回應。 否則,會提供 304 - 未修改的回應。 |
Date |
當從快取提供服務時,如果原始回應中未提供 Date 標頭,則由中介軟體設定 Date 標頭。 |
Content-Length |
當從快取提供服務時,如果原始回應中未提供 Content-Length 標頭,則由中介軟體設定 Content-Length 標頭。 |
Age |
原始回應中傳送的 Age 標頭會遭忽略。 中介軟體會在提供快取回應時計算新的值。 |
快取會遵守要求 Cache-Control 指示詞
中介軟體遵守 RFC 9111:HTTP 快取規則 (第 5.2 節。快取控制)。 規則需要快取,才能接受用戶端所傳送的有效 Cache-Control
標頭。 在規格下,用戶端可以使用標頭值 no-cache
提出要求,並強制伺服器為每個要求產生新的回應。 目前,使用中介軟體時,沒有任何開發人員控制此快取行為,因為中介軟體遵守官方快取規格。
若要進一步控制快取行為,請探索 ASP.NET Core 的其他快取功能。 請參閱下列主題的說明:
疑難排解
如果快取行為不如預期,請確認回應可進行快取且能夠從快取提供。 檢查要求的傳入標頭和回應的傳出標頭。 啟用記錄以協助偵錯。
測試快取行為並進行疑難排解時,瀏覽器可能會設定要求標頭,並以不想要的方式影響快取。 例如,瀏覽器可能會在重新整理頁面時,將 Cache-Control
標頭設定為 no-cache
或 max-age=0
。 下列工具可以明確設定要求標頭,並偏好用於測試快取:
快取的條件
- 要求必須產生具有 200 (OK) 狀態碼的伺服器回應。
- 要求方法必須是 GET 或 HEAD。
- 在
Startup.Configure
中,回應快取中介軟體必須放在需要快取的中介軟體之前。 如需詳細資訊,請參閱 ASP.NET Core 中介軟體。 - 標頭
Authorization
不得存在。 Cache-Control
標頭參數必須為有效,而且回應必須標示public
且未標示private
。- 如果
Cache-Control
標頭不存在,則Pragma: no-cache
標頭不得存在,因為Cache-Control
標頭會覆寫存在的Pragma
標頭。 - 標頭
Set-Cookie
不得存在。 Vary
標頭參數必須有效且不等於*
。Content-Length
標頭值 (如有設定) 必須符合回應主體的大小。- IHttpSendFileFeature 未使用。
- 回應不得過時,如
Expires
標頭和max-age
與s-maxage
快取指示詞所指定。 - 回應緩衝必須成功。 回應的大小必須小於設定或預設 SizeLimit。 回應的主體大小必須小於所設定或預設 MaximumBodySize。
- 根據 RFC 9111:HTTP 快取,回應必須可快取。 例如,
no-store
指示詞不能存在於要求或回應標頭欄位中。 如需詳細資訊,請參閱 RFC 9111:HTTP 快取 (第 3 節:將回應儲存在快取中。
注意
用於產生安全權杖的 Antiforgery 系統可防止跨網站偽造要求 (CSRF) 攻擊將 Cache-Control
和 Pragma
標頭設定為 no-cache
,以便回應不會被快取。 如需如何停用 HTML 表單元素的反偽造權杖資訊,請參閱在 ASP.NET Core 中防止跨網站偽造要求 (XSRF/CSRF) 攻擊。