Nguon: Microsoft Learn · .NET 8.0

Response Caching Middleware (Phần mềm trung gian Cache phản hồi) trong ASP.NET Core

Nguồn: Response Caching Middleware in ASP.NET Core

Bởi John Luo và Rick Anderson

Bài viết này giải thích cách cấu hình Response Caching Middleware trong ứng dụng ASP.NET Core. Middleware xác định khi nào response (phản hồi) có thể được cache (lưu vào bộ nhớ đệm), lưu trữ response, và phục vụ response từ cache. Để giới thiệu về HTTP caching và attribute [ResponseCache], xem Response Caching.

Response caching middleware (phần mềm trung gian cache phản hồi) cho phép cache response của server dựa trên HTTP Cache-Control headers.

Output caching (có trong .NET 7 trở lên) là phương pháp tốt hơn cho ứng dụng UI. Trong kịch bản đó, cấu hình xác định những gì cần cache độc lập với HTTP headers.

Để kiểm thử response caching, dùng Fiddler hoặc công cụ khác có thể đặt request headers một cách rõ ràng. Việc đặt headers rõ ràng là ưu tiên cho việc kiểm thử caching.

Cấu hình

Trong Program.cs, thêm Response Caching Middleware services AddResponseCaching vào service collection và cấu hình ứng dụng sử dụng middleware với extension method UseResponseCaching. UseResponseCaching thêm middleware vào request processing pipeline:

csharp
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddResponseCaching();

var app = builder.Build();

app.UseHttpsRedirection();

// UseCors phải được gọi trước UseResponseCaching
//app.UseCors();

app.UseResponseCaching();

Cảnh báo: UseCors phải được gọi trước UseResponseCaching khi dùng CORS middleware.

Ứng dụng mẫu thêm headers để kiểm soát caching trên các request tiếp theo:

csharp
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddResponseCaching();

var app = builder.Build();

app.UseHttpsRedirection();

// UseCors phải được gọi trước 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();

Các headers trên không được ghi vào response và bị ghi đè khi controller, action, hoặc Razor Page:

Response Caching Middleware chỉ cache response của server với status code 200 (OK). Các response khác, bao gồm error pages (trang lỗi), đều bị middleware bỏ qua.

Cảnh báo: Các response chứa nội dung cho client đã xác thực phải được đánh dấu là không thể cache để ngăn middleware lưu trữ và phục vụ những response đó. Xem phần Điều kiện để cache để biết chi tiết về cách middleware xác định response có thể được cache hay không.

Tùy chọn

Các tùy chọn response caching được hiển thị trong bảng sau.

Tùy chọnMô tả
MaximumBodySizeKích thước lớn nhất có thể cache của response body (nội dung phản hồi) tính bằng byte. Giá trị mặc định là 64 * 1024 * 1024 (64 MB).
SizeLimitGiới hạn kích thước cho response cache middleware tính bằng byte. Giá trị mặc định là 100 * 1024 * 1024 (100 MB).
UseCaseSensitivePathsXác định xem response có được cache trên các path (đường dẫn) phân biệt chữ hoa/thường hay không. Giá trị mặc định là false.

Ví dụ sau cấu hình middleware để:

csharp
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddResponseCaching(options =>
{
    options.MaximumBodySize = 1024;
    options.UseCaseSensitivePaths = true;
});

var app = builder.Build();

app.UseHttpsRedirection();

// UseCors phải được gọi trước 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

Khi dùng MVC, web API controllers, hoặc Razor Pages page models, attribute [ResponseCache] chỉ định các tham số cần thiết để đặt headers thích hợp cho response caching. Tham số duy nhất của attribute [ResponseCache] thực sự yêu cầu middleware là VaryByQueryKeys, không tương ứng với HTTP header thực tế.

Khi không dùng attribute [ResponseCache], response caching có thể biến đổi với VaryByQueryKeys. Dùng ResponseCachingFeature trực tiếp từ HttpContext.Features:

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

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

Dùng giá trị duy nhất * trong VaryByQueryKeys sẽ biến đổi cache theo tất cả các query parameter (tham số truy vấn) của request.

HTTP headers được dùng bởi Response Caching Middleware

Bảng sau cung cấp thông tin về HTTP headers ảnh hưởng đến response caching.

HeaderChi tiết
AuthorizationResponse không được cache nếu header này tồn tại.
Cache-ControlMiddleware chỉ xem xét cache các response được đánh dấu với cache directive public. Kiểm soát caching với các tham số: max-age, max-stale†, min-fresh, must-revalidate, no-cache, no-store, only-if-cached, private, public, s-maxage, proxy-revalidate‡. †Nếu không có giới hạn nào được chỉ định cho max-stale, middleware không thực hiện hành động nào. ‡proxy-revalidate có tác dụng giống must-revalidate.
PragmaHeader Pragma: no-cache trong request tạo ra hiệu ứng tương tự Cache-Control: no-cache. Header này bị ghi đè bởi các directive liên quan trong header Cache-Control nếu có. Được xem xét để tương thích ngược với HTTP/1.0.
Set-CookieResponse không được cache nếu header này tồn tại. Bất kỳ middleware nào trong pipeline xử lý request đặt một hoặc nhiều cookie sẽ ngăn Response Caching Middleware cache response (ví dụ, cookie-based TempData provider).
VaryHeader Vary được dùng để biến đổi cached response theo header khác. Ví dụ, cache response theo encoding bằng cách thêm header Vary: Accept-Encoding, cache response cho các request có headers Accept-Encoding: gzipAccept-Encoding: text/plain riêng biệt. Response với giá trị header * không bao giờ được lưu.
ExpiresResponse được coi là cũ bởi header này sẽ không được lưu hoặc truy xuất trừ khi bị ghi đè bởi các header Cache-Control khác.
If-None-MatchResponse đầy đủ được phục vụ từ cache nếu giá trị không phải *ETag của response không khớp với bất kỳ giá trị nào được cung cấp. Nếu không, một response 304 (Not Modified) được phục vụ.
If-Modified-SinceNếu header If-None-Match không có, response đầy đủ được phục vụ từ cache nếu ngày cached response mới hơn giá trị được cung cấp. Nếu không, response 304 - Not Modified được phục vụ.
DateKhi phục vụ từ cache, header Date được đặt bởi middleware nếu nó không được cung cấp trong response gốc.
Content-LengthKhi phục vụ từ cache, header Content-Length được đặt bởi middleware nếu nó không được cung cấp trong response gốc.
AgeHeader Age được gửi trong response gốc bị bỏ qua. Middleware tính toán giá trị mới khi phục vụ cached response.

Caching tuân theo Cache-Control directives của request

Middleware tuân theo các quy tắc của RFC 9111: HTTP Caching (Section 5.2. Cache-Control). Các quy tắc yêu cầu cache phải tôn trọng header Cache-Control hợp lệ được gửi bởi client. Theo specification (đặc tả), client có thể thực hiện request với giá trị header no-cache và buộc server tạo response mới cho mỗi request. Hiện tại, không có developer control (kiểm soát của nhà phát triển) nào đối với hành vi caching này khi sử dụng middleware vì middleware tuân theo specification caching chính thức.

Để kiểm soát hành vi caching nhiều hơn, hãy khám phá các tính năng caching khác của ASP.NET Core:

Xử lý sự cố

Response Caching Middleware dùng IMemoryCache, có dung lượng giới hạn. Khi dung lượng bị vượt quá, memory cache sẽ được compact (nén).

Nếu hành vi caching không như mong đợi, hãy xác nhận rằng các response có thể được cache và có khả năng được phục vụ từ cache. Kiểm tra các incoming headers của request và outgoing headers của response. Bật logging (ghi nhật ký) để hỗ trợ debug.

Khi kiểm thử và xử lý sự cố hành vi caching, trình duyệt thường đặt request headers ngăn caching. Ví dụ, trình duyệt có thể đặt header Cache-Control thành no-cache hoặc max-age=0 khi làm mới trang. Fiddler và các công cụ khác có thể đặt request headers một cách rõ ràng và được ưu tiên để kiểm thử caching.

Điều kiện để cache

Lưu ý: Hệ thống Antiforgery (chống giả mạo) để tạo secure tokens (token bảo mật) ngăn Cross-Site Request Forgery (CSRF) tấn công đặt các header Cache-ControlPragma thành no-cache để các response không được cache.