ASP.NET Core中的回應快取中介軟體

作者: John 一Rick Anderson

本文說明如何在 ASP.NET Core應用程式中設定回應快取中介軟體。 中介軟體會判斷回應何時可快取、儲存回應,以及從快取提供回應。 如需 HTTP 快取和 [ResponseCache] 屬性的簡介,請參閱 回應快取

回應快取中介軟體:

  • 根據 HTTP 快取標頭啟用快取伺服器回應。 實作標準 HTTP 快取語意。 以 HTTP 快取標頭為基礎的快取,例如 Proxy。
  • 通常對頁面之類的 Razor UI 應用程式而言並不有説明,因為瀏覽器通常會設定防止快取的要求標頭。 系統會將輸出快取視為下一版 ASP.NET Core,這會讓 UI 應用程式受益。 使用輸出快取時,組態會決定應該獨立于 HTTP 標頭中快取的內容。 如需詳細資訊,請參閱這個 GitHub 問題 \(英文\)。
  • 對於符合快 取條件 的用戶端,公用 GET 或 HEAD API 要求可能很有説明。

使用 FiddlerPostman或其他可明確設定要求標頭的工具。 明確設定標頭是測試快取的慣用專案。 如需詳細資訊,請參閱 疑難排解

設定

在 中 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();

警告

UseCors在使用CORS 中介軟體之前 UseResponseCaching ,必須先呼叫 。

範例應用程式會新增標頭,以控制後續要求的快取:

  • 快取控制:快取最多 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) 狀態碼的伺服器回應。 中介軟體會忽略任何其他回應,包括 錯誤頁面

警告

包含已驗證用戶端內容的回應必須標示為不可快取,以防止中介軟體儲存及處理這些回應。 如需中介軟體如何判斷回應是否可快取的詳細資訊,請參閱 快取的條件

上述程式碼通常不會將快取的值傳回瀏覽器。 使用 FiddlerPostman或其他可明確設定要求標頭的工具,並偏好用於測試快取。 如需詳細資訊,請參閱本文中的 疑難排解

選項

下表顯示回應快取選項。

選項 Description
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 頁面頁面模型時, [ResponseCache] 屬性會指定設定回應快取適當標頭所需的參數。 嚴格要求中介軟體的屬性 [ResponseCache] 唯一參數是 VaryByQueryKeys ,這不會對應到實際的 HTTP 標頭。 如需詳細資訊,請參閱ASP.NET Core中的回應快取

不使用 [ResponseCache] 屬性時,回應快取可能會隨著 VaryByQueryKeys 而有所不同。 ResponseCachingFeature直接從HttpCoNtext.Features使用 :

var responseCachingFeature = context.HttpContext.Features.Get<IResponseCachingFeature>();

if (responseCachingFeature != null)
{
    responseCachingFeature.VaryByQueryKeys = new[] { "MyKey" };
}

使用等於 * 中的 VaryByQueryKeys 單一值會因所有要求查詢參數而有所不同。

回應快取中介軟體所使用的 HTTP 標頭

下表提供影響回應快取的 HTTP 標頭相關資訊。

標頭 詳細資料
Authorization 如果標頭存在,則不會快取回應。
Cache-Control 中介軟體只會考慮使用快取指示詞標記的 public 快取回應。 使用下列參數控制快取:
  • max-age
  • max-stale†
  • min-fresh
  • must-revalidate
  • no-cache
  • no-store
  • only-if-cached
  • private
  • public
  • s-maxage
  • proxy-revalidate*
†如果未指定任何限制, max-stale 中介軟體就不會採取任何動作。
proxy-revalidate 的效果與 相同 must-revalidate

如需詳細資訊,請參閱 RFC 7231:要求Cache-Control指示詞
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 標頭就會由中介軟體設定。
Content-Length 從快取提供時,如果未在原始回應上提供標頭, Content-Length 標頭就會由中介軟體設定。
Age 系統會 Age 忽略原始回應中傳送的標頭。 中介軟體會在提供快取的回應時計算新的值。

快取會遵循要求Cache-Control指示詞

中介軟體會遵守 HTTP 1.1 快取規格的規則。 這些規則需要快取才能接受用戶端所傳送的有效 Cache-Control 標頭。 在規格下,用戶端可以使用標頭值提出要求 no-cache ,並強制服務器為每個要求產生新的回應。 目前,使用中介軟體時,沒有任何開發人員控制此快取行為,因為中介軟體遵守官方快取規格。

若要進一步控制快取行為,請探索 ASP.NET Core的其他快取功能。 請參閱下列主題:

疑難排解

回應快取中介軟體會使用 IMemoryCache 具有有限容量的 。 超過容量時, 會壓縮記憶體快取

如果快取行為不如預期,請確認回應是可快取的,而且能夠從快取提供。 檢查要求的傳入標頭和回應的傳出標頭。 啟用 記錄 以協助偵錯。

當測試和疑難排解快取行為時,瀏覽器通常會設定防止快取的要求標頭。 例如,瀏覽器可能會在重新整理頁面時, Cache-Control 將標頭設定為 no-cachemax-age=0FiddlerPostman和其他工具可以明確設定要求標頭,並偏好用於測試快取。

快取的條件

  • 要求必須產生具有 200 (OK) 狀態碼的伺服器回應。
  • 要求方法必須是 GET 或 HEAD。
  • 回應快取中介軟體必須放在需要快取的中介軟體之前。 如需詳細資訊,請參閱ASP.NET Core中介軟體
  • Authorization標頭不得存在。
  • Cache-Control 標頭參數必須有效,且回應必須標示 public 且未標示 private
  • Pragma: no-cache如果 Cache-Control 標頭不存在,則標頭不得存在,因為 Cache-Control 標頭會在存在時覆寫 Pragma 標頭。
  • Set-Cookie標頭不得存在。
  • Vary 標頭參數必須有效且不等於 *
  • 如果設定) 必須符合回應本文的大小,標頭 Content-Length 值 (。
  • IHttpSendFileFeature未使用 。
  • 回應不得過期,如標頭和 max-age 和 快 s-maxage 取指示詞所指定 Expires
  • 回應緩衝必須成功。 回應的大小必須小於設定或預設 SizeLimit 。 回應的本文大小必須小於設定或預設 MaximumBodySize
  • 回應必須根據 RFC 7234 規格進行快取。 例如, no-store 指示詞不得存在於要求或回應標頭欄位中。 如需詳細資訊,請參閱 第 3 節:將回應儲存在RFC 7234 的快取中。

注意

用來產生安全權杖的 Antiforgery 系統,以防止跨網站偽造要求 (CSRF) 攻擊將 和 Pragma 標頭設定 Cache-Controlno-cache ,以便不會快取回應。 如需如何停用 HTML 表單元素的反錯權杖資訊,請參閱防止跨網站偽造 (XSRF/CSRF) 攻擊 ASP.NET Core

其他資源

本文說明如何在 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();
    });
}

警告

UseCors在使用CORS 中介軟體之前 UseResponseCaching ,必須先呼叫 。

範例應用程式會新增標頭,以控制後續要求的快取:

  • 快取控制:快取最多 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) 狀態碼的伺服器回應。 中介軟體會忽略任何其他回應,包括 錯誤頁面

警告

包含已驗證用戶端內容的回應必須標示為不可快取,以防止中介軟體儲存及處理這些回應。 如需中介軟體如何判斷回應是否可快取的詳細資訊,請參閱 快取的條件

選項

下表顯示回應快取選項。

選項 Description
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 頁面頁面模型時, [ResponseCache] 屬性會指定設定回應快取適當標頭所需的參數。 嚴格要求中介軟體的屬性 [ResponseCache] 唯一參數是 VaryByQueryKeys ,這不會對應到實際的 HTTP 標頭。 如需詳細資訊,請參閱ASP.NET Core中的回應快取

不使用 [ResponseCache] 屬性時,回應快取可能會隨著 VaryByQueryKeys 而有所不同。 ResponseCachingFeature直接從HttpCoNtext.Features使用 :

var responseCachingFeature = context.HttpContext.Features.Get<IResponseCachingFeature>();

if (responseCachingFeature != null)
{
    responseCachingFeature.VaryByQueryKeys = new[] { "MyKey" };
}

使用等於 * 中的 VaryByQueryKeys 單一值會因所有要求查詢參數而有所不同。

回應快取中介軟體所使用的 HTTP 標頭

下表提供影響回應快取的 HTTP 標頭相關資訊。

標頭 詳細資料
Authorization 如果標頭存在,則不會快取回應。
Cache-Control 中介軟體只會考慮使用快取指示詞標記的 public 快取回應。 使用下列參數控制快取:
  • max-age
  • max-stale†
  • min-fresh
  • must-revalidate
  • no-cache
  • no-store
  • only-if-cached
  • private
  • public
  • s-maxage
  • proxy-revalidate*
†如果未指定任何限制, max-stale 中介軟體就不會採取任何動作。
proxy-revalidate 的效果與 相同 must-revalidate

如需詳細資訊,請參閱 RFC 7231:要求Cache-Control指示詞
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 標頭就會由中介軟體設定。
Content-Length 從快取提供時,如果未在原始回應上提供標頭, Content-Length 標頭就會由中介軟體設定。
Age 系統會 Age 忽略原始回應中傳送的標頭。 中介軟體會在提供快取的回應時計算新的值。

快取會遵循要求Cache-Control指示詞

中介軟體會遵守 HTTP 1.1 快取規格的規則。 這些規則需要快取才能接受用戶端所傳送的有效 Cache-Control 標頭。 在規格下,用戶端可以使用標頭值提出要求 no-cache ,並強制服務器為每個要求產生新的回應。 目前,使用中介軟體時,沒有任何開發人員控制此快取行為,因為中介軟體遵守官方快取規格。

若要進一步控制快取行為,請探索 ASP.NET Core的其他快取功能。 請參閱下列主題:

疑難排解

如果快取行為不如預期,請確認回應是可快取的,而且能夠從快取提供。 檢查要求的傳入標頭和回應的傳出標頭。 啟用 記錄 以協助偵錯。

測試和疑難排解快取行為時,瀏覽器可能會設定要求標頭,以不想要的方式影響快取。 例如,瀏覽器可能會在重新整理頁面時, Cache-Control 將標頭設定為 no-cachemax-age=0 。 下列工具可以明確設定要求標頭,而且是測試快取的慣用工具:

快取的條件

  • 要求必須產生具有 200 (OK) 狀態碼的伺服器回應。
  • 要求方法必須是 GET 或 HEAD。
  • 在 中 Startup.Configure ,必須在需要快取的中介軟體之前放置回應快取中介軟體。 如需詳細資訊,請參閱ASP.NET Core中介軟體
  • Authorization標頭不得存在。
  • Cache-Control 標頭參數必須有效,且回應必須標示 public 且未標示 private
  • Pragma: no-cache如果 Cache-Control 標頭不存在,則標頭不得存在,因為 Cache-Control 標頭會在存在時覆寫 Pragma 標頭。
  • Set-Cookie標頭不得存在。
  • Vary 標頭參數必須有效且不等於 *
  • 如果設定) 必須符合回應本文的大小,標頭 Content-Length 值 (。
  • IHttpSendFileFeature未使用 。
  • 回應不得過期,如標頭和 max-age 和 快 s-maxage 取指示詞所指定 Expires
  • 回應緩衝必須成功。 回應的大小必須小於設定或預設 SizeLimit 。 回應的本文大小必須小於設定或預設 MaximumBodySize
  • 回應必須根據 RFC 7234 規格進行快取。 例如, no-store 指示詞不得存在於要求或回應標頭欄位中。 如需詳細資訊,請參閱 第 3 節:將回應儲存在RFC 7234 的快取中。

注意

用來產生安全權杖的 Antiforgery 系統,以防止跨網站偽造要求 (CSRF) 攻擊將 和 Pragma 標頭設定 Cache-Controlno-cache ,以便不會快取回應。 如需如何停用 HTML 表單元素的反錯權杖資訊,請參閱防止跨網站偽造 (XSRF/CSRF) 攻擊 ASP.NET Core

其他資源