Middleware de almacenamiento en caché de respuestas en ASP.NET Core

Por John Luo

En este artículo se explica cómo configurar el middleware de almacenamiento en caché de respuestas ASP.NET Core aplicación. El middleware determina cuándo se pueden almacenar en caché las respuestas, almacena las respuestas y sirve las respuestas de la memoria caché. Para obtener una introducción al almacenamiento en caché HTTP y [ResponseCache] el atributo , vea Almacenamiento en caché de respuesta.

Vea o descargue el código de ejemplo (cómo descargarlo)

Configuración

El middleware de almacenamiento en caché de respuestas está disponible implícitamente ASP.NET Core aplicaciones a través del marco compartido.

En Startup.ConfigureServices , agregue el middleware de almacenamiento en caché de respuesta a la colección de servicios:

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCaching();
    services.AddRazorPages();
}

Configure la aplicación para que use el middleware con el método de extensión , que agrega el middleware a UseResponseCaching la canalización de procesamiento de solicitudes en 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();
    });
}

Advertencia

UseCorsSe debe llamar a antes UseResponseCaching cuando se usa el middleware de CORS.

La aplicación de ejemplo agrega encabezados para controlar el almacenamiento en caché en las solicitudes posteriores:

  • Cache-Control:almacena en caché las respuestas que se pueden almacenar en caché durante un máximo de 10 segundos.
  • Vary:configura el middleware para que sirva una respuesta almacenada en caché solo si el encabezado Accept-Encoding de las solicitudes posteriores coincide con el de la solicitud original.
// 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();
});

Los encabezados anteriores no se escriben en la respuesta y se reemplazan cuando un controlador, una acción o una Razor página:

El middleware de almacenamiento en caché de respuestas solo almacena en caché las respuestas del servidor que tienen como resultado un código de estado 200 (correcto). El middleware omite cualquier otra respuesta, incluidas las páginas de error.

Advertencia

Las respuestas que contienen contenido para los clientes autenticados deben marcarse como no almacenables en caché para evitar que el middleware almacene y atendiendo esas respuestas. Consulte Condiciones para el almacenamiento en caché para obtener más información sobre cómo el middleware determina si una respuesta se puede almacenar en caché.

Opciones

Las opciones de almacenamiento en caché de respuestas se muestran en la tabla siguiente.

Opción Descripción
MaximumBodySize Tamaño mayor que se puede almacenar en caché para el cuerpo de la respuesta en bytes. El valor predeterminado es 64 * 1024 * 1024 (64 MB).
SizeLimit Límite de tamaño del middleware de caché de respuestas en bytes. El valor predeterminado es 100 * 1024 * 1024 (100 MB).
UseCaseSensitivePaths Determina si las respuestas se almacenan en caché en rutas de acceso que distinguen mayúsculas de minúsculas. El valor predeterminado es false.

En el ejemplo siguiente se configura el middleware para:

  • Almacenar en caché las respuestas con un tamaño de cuerpo menor o igual que 1024 bytes.
  • Almacene las respuestas por rutas de acceso que distinguen mayúsculas de minúsculas. Por ejemplo, /page1 y se almacenan por /Page1 separado.
services.AddResponseCaching(options =>
{
    options.MaximumBodySize = 1024;
    options.UseCaseSensitivePaths = true;
});

VaryByQueryKeys

Cuando se usan controladores de MVC/API web o modelos de página de Pages, el atributo especifica los parámetros necesarios para establecer los encabezados adecuados para el almacenamiento en caché Razor [ResponseCache] de respuestas. El único parámetro del atributo que requiere estrictamente el middleware es , que [ResponseCache] no corresponde a un encabezado HTTP VaryByQueryKeys real. Para obtener más información, vea Almacenamiento en caché de respuestas en ASP.NET Core.

Cuando no se usa el [ResponseCache] atributo , el almacenamiento en caché de respuestas puede variar con VaryByQueryKeys . Use directamente ResponseCachingFeature desde HttpContext.Features:

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

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

El uso de un valor único igual a * en varía la memoria caché según todos los parámetros de consulta de VaryByQueryKeys solicitud.

Encabezados HTTP usados por el middleware de almacenamiento en caché de respuestas

En la tabla siguiente se proporciona información sobre los encabezados HTTP que afectan al almacenamiento en caché de respuestas.

Header Detalles
Authorization La respuesta no se almacena en caché si el encabezado existe.
Cache-Control El middleware solo tiene en cuenta las respuestas de almacenamiento en caché marcadas con la public directiva de caché. Controle el almacenamiento en caché con los parámetros siguientes:
  • max-age
  • max-stale†
  • min-fresh
  • must-revalidate
  • sin caché
  • no-store
  • only-if-cached
  • privado
  • público
  • s-maxage
  • proxy-revalidate‡
†si no se especifica ningún límite para max-stale , el middleware no realiza ninguna acción.
‡tiene proxy-revalidate el mismo efecto que must-revalidate .

Para obtener más información, vea RFC 7231: Request Cache-Control Directives.
Pragma Un Pragma: no-cache encabezado de la solicitud produce el mismo efecto que Cache-Control: no-cache . Este encabezado se reemplaza por las directivas pertinentes en el Cache-Control encabezado, si está presente. Se considera por compatibilidad con versiones anteriores con HTTP/1.0.
Set-Cookie La respuesta no se almacena en caché si el encabezado existe. Cualquier middleware de la canalización de procesamiento de solicitudes que establece uno o más de impide que el middleware de almacenamiento en caché de respuestas almacena en caché la respuesta cookie (por ejemplo, el cookie proveedor TempData basadoen ).
Vary El Vary encabezado se usa para variar la respuesta almacenada en caché por otro encabezado. Por ejemplo, almacenar en caché las respuestas mediante codificación mediante la inclusión del encabezado , que almacena en caché las respuestas de Vary: Accept-Encoding las solicitudes con encabezados y por Accept-Encoding: gzip Accept-Encoding: text/plain separado. Nunca se almacena una respuesta con un valor * de encabezado de .
Expires Una respuesta que este encabezado considera obsoleta no se almacena ni recupera a menos que se invalide por otros Cache-Control encabezados.
If-None-Match La respuesta completa se proporciona desde la memoria caché si el valor no es y el valor de la respuesta no coincide * con ninguno de los valores ETag proporcionados. De lo contrario, se sirve una respuesta 304 (no modificada).
If-Modified-Since Si el encabezado no está presente, se proporciona una respuesta completa desde la memoria caché si la fecha de respuesta almacenada en caché es más If-None-Match reciente que el valor proporcionado. De lo contrario, se sirve una respuesta 304 - No modificado.
Date Al servir desde la memoria caché, el middleware establece el encabezado si no se proporcionó Date en la respuesta original.
Content-Length Al servir desde la memoria caché, el middleware establece el encabezado si no se proporcionó Content-Length en la respuesta original.
Age Se Age omite el encabezado enviado en la respuesta original. El middleware calcula un nuevo valor al atender una respuesta almacenada en caché.

El almacenamiento en caché respeta las directivas Cache-Control solicitudes

El middleware respeta las reglas de la especificación de almacenamiento en caché HTTP 1.1. Las reglas requieren que una memoria caché respeta un encabezado Cache-Control válido enviado por el cliente. En la especificación , un cliente puede realizar solicitudes con un valor de encabezado y forzar al servidor a generar una nueva respuesta no-cache para cada solicitud. Actualmente, no hay ningún control del desarrollador sobre este comportamiento de almacenamiento en caché al usar el middleware porque el middleware se adhiere a la especificación de almacenamiento en caché oficial.

Para obtener más control sobre el comportamiento del almacenamiento en caché, explore otras características de almacenamiento en caché ASP.NET Core. Vea los siguientes temas:

Solución de problemas

Si el comportamiento del almacenamiento en caché no es el esperado, confirme que las respuestas se pueden almacenar en caché y pueden servirse desde la memoria caché. Examine los encabezados entrantes de la solicitud y los encabezados salientes de la respuesta. Habilite el registro para ayudar con la depuración.

Al probar y solucionar problemas de comportamiento de almacenamiento en caché, un explorador puede establecer encabezados de solicitud que afectan al almacenamiento en caché de maneras no deseadas. Por ejemplo, un explorador puede establecer el Cache-Control encabezado en o al actualizar una no-cache max-age=0 página. Las herramientas siguientes pueden establecer explícitamente encabezados de solicitud y son preferidas para probar el almacenamiento en caché:

Condiciones para el almacenamiento en caché

  • La solicitud debe dar lugar a una respuesta del servidor con un código de estado 200 (correcto).
  • El método de solicitud debe ser GET o HEAD.
  • En Startup.Configure , el middleware de almacenamiento en caché de respuesta debe colocarse antes que el middleware que requiere almacenamiento en caché. Para obtener más información, vea Middleware de ASP.NET Core.
  • El Authorization encabezado no debe estar presente.
  • Cache-Control Los parámetros de encabezado deben ser válidos y la respuesta debe marcarse public y no marcarse private como .
  • El encabezado no debe estar presente si el encabezado no está presente, ya que el Pragma: no-cache encabezado invalida el encabezado cuando está Cache-Control Cache-Control Pragma presente.
  • El Set-Cookie encabezado no debe estar presente.
  • Vary Los parámetros de encabezado deben ser válidos y no iguales a * .
  • El Content-Length valor de encabezado (si se establece) debe coincidir con el tamaño del cuerpo de la respuesta.
  • No IHttpSendFileFeature se usa .
  • La respuesta no debe estar obsoleta según lo especificado por el Expires encabezado y las directivas de caché y max-age s-maxage .
  • El almacenamiento en búfer de respuesta debe ser correcto. El tamaño de la respuesta debe ser menor que el configurado o SizeLimit predeterminado. El tamaño del cuerpo de la respuesta debe ser menor que el configurado o MaximumBodySize predeterminado.
  • La respuesta debe ser almacenable en caché según las especificaciones de RFC 7234. Por ejemplo, la no-store directiva no debe existir en los campos de encabezado de solicitud o respuesta. Consulte Sección 3: Almacenamiento de respuestas en cachés de RFC 7234 para obtener más información.

Nota

El sistema Antiforgery para generar tokens seguros para evitar ataques de falsificación de solicitud entre sitios (CSRF) establece los encabezados y en para que las respuestas no se almacenen en Cache-Control Pragma no-cache caché. Para obtener información sobre cómo deshabilitar los tokens antiforgeria para elementos de formulario HTML, vea Evitar ataques de falsificación de solicitud entre sitios (XSRF/CSRF) en ASP.NET Core .

Recursos adicionales

En este artículo se explica cómo configurar el middleware de almacenamiento en caché de respuestas en ASP.NET Core aplicación. El middleware determina cuándo se pueden almacenar en caché las respuestas, almacena las respuestas y sirve las respuestas de la memoria caché. Para obtener una introducción al almacenamiento en caché HTTP y [ResponseCache] el atributo , vea Almacenamiento en caché de respuesta.

Vea o descargue el código de ejemplo (cómo descargarlo)

Configuración

Use el Microsoft.AspNetCore.App metapaquete o agregue una referencia de paquete al paquete Microsoft.AspNetCore.ResponseCaching.

En Startup.ConfigureServices , agregue el middleware de almacenamiento en caché de respuesta a la colección de servicios:

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCaching();
    services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

Configure la aplicación para que use el middleware con el método de extensión , que agrega el middleware a UseResponseCaching la canalización de procesamiento de solicitudes en Startup.Configure :

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseStaticFiles();

    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.UseMvc();
}

La aplicación de ejemplo agrega encabezados para controlar el almacenamiento en caché en las solicitudes posteriores:

  • Cache-Control:almacena en caché las respuestas que se pueden almacenar en caché durante un máximo de 10 segundos.
  • Vary:configura el middleware para que sirva una respuesta almacenada en caché solo si el encabezado Accept-Encoding de las solicitudes posteriores coincide con el de la solicitud original.
// 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();
});

Los encabezados anteriores no se escriben en la respuesta y se reemplazan cuando un controlador, una acción o una Razor página:

El middleware de almacenamiento en caché de respuestas solo almacena en caché las respuestas del servidor que tienen como resultado un código de estado 200 (correcto). El middleware omite cualquier otra respuesta, incluidas las páginas de error.

Advertencia

Las respuestas que contienen contenido para los clientes autenticados deben marcarse como no almacenables en caché para evitar que el middleware almacene y atendiendo esas respuestas. Consulte Condiciones para el almacenamiento en caché para obtener más información sobre cómo el middleware determina si una respuesta se puede almacenar en caché.

Opciones

Las opciones de almacenamiento en caché de respuestas se muestran en la tabla siguiente.

Opción Descripción
MaximumBodySize Tamaño mayor que se puede almacenar en caché para el cuerpo de la respuesta en bytes. El valor predeterminado es 64 * 1024 * 1024 (64 MB).
SizeLimit Límite de tamaño del middleware de caché de respuestas en bytes. El valor predeterminado es 100 * 1024 * 1024 (100 MB).
UseCaseSensitivePaths Determina si las respuestas se almacenan en caché en rutas de acceso que distinguen mayúsculas de minúsculas. El valor predeterminado es false.

En el ejemplo siguiente se configura el middleware para:

  • Almacenar en caché las respuestas con un tamaño de cuerpo menor o igual que 1024 bytes.
  • Almacene las respuestas por rutas de acceso que distinguen mayúsculas de minúsculas. Por ejemplo, /page1 y se almacenan por /Page1 separado.
services.AddResponseCaching(options =>
{
    options.MaximumBodySize = 1024;
    options.UseCaseSensitivePaths = true;
});

VaryByQueryKeys

Cuando se usan controladores de MVC/API web o modelos de página de Pages, el atributo especifica los parámetros necesarios para establecer los encabezados adecuados para el almacenamiento en caché Razor [ResponseCache] de respuestas. El único parámetro del atributo que requiere estrictamente el middleware es , que [ResponseCache] no corresponde a un encabezado HTTP VaryByQueryKeys real. Para obtener más información, vea Almacenamiento en caché de respuestas en ASP.NET Core.

Cuando no se usa el [ResponseCache] atributo , el almacenamiento en caché de respuestas puede variar con VaryByQueryKeys . Use directamente ResponseCachingFeature desde HttpContext.Features:

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

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

El uso de un valor único igual a * en varía la memoria caché según todos los parámetros de consulta de VaryByQueryKeys solicitud.

Encabezados HTTP usados por el middleware de almacenamiento en caché de respuestas

En la tabla siguiente se proporciona información sobre los encabezados HTTP que afectan al almacenamiento en caché de respuestas.

Header Detalles
Authorization La respuesta no se almacena en caché si el encabezado existe.
Cache-Control El middleware solo tiene en cuenta las respuestas de almacenamiento en caché marcadas con la public directiva de caché. Controle el almacenamiento en caché con los parámetros siguientes:
  • max-age
  • max-stale†
  • min-fresh
  • must-revalidate
  • sin caché
  • no-store
  • only-if-cached
  • privado
  • público
  • s-maxage
  • proxy-revalidate‡
†si no se especifica ningún límite para max-stale , el middleware no realiza ninguna acción.
‡tiene proxy-revalidate el mismo efecto que must-revalidate .

Para obtener más información, vea RFC 7231: Request Cache-Control Directives.
Pragma Un Pragma: no-cache encabezado de la solicitud produce el mismo efecto que Cache-Control: no-cache . Este encabezado se reemplaza por las directivas pertinentes en el Cache-Control encabezado, si está presente. Se considera por compatibilidad con versiones anteriores con HTTP/1.0.
Set-Cookie La respuesta no se almacena en caché si el encabezado existe. Cualquier middleware de la canalización de procesamiento de solicitudes que establece uno o más de impide que el middleware de almacenamiento en caché de respuestas almacena en caché la respuesta cookie (por ejemplo, el cookie proveedor TempData basadoen ).
Vary El Vary encabezado se usa para variar la respuesta almacenada en caché por otro encabezado. Por ejemplo, almacenar en caché las respuestas mediante codificación mediante la inclusión del encabezado , que almacena en caché las respuestas de Vary: Accept-Encoding las solicitudes con encabezados y por Accept-Encoding: gzip Accept-Encoding: text/plain separado. Nunca se almacena una respuesta con un valor * de encabezado de .
Expires Una respuesta que este encabezado considera obsoleta no se almacena ni recupera a menos que se invalide por otros Cache-Control encabezados.
If-None-Match La respuesta completa se proporciona desde la memoria caché si el valor no es y el valor de la respuesta no coincide * con ninguno de los valores ETag proporcionados. De lo contrario, se sirve una respuesta 304 (no modificada).
If-Modified-Since Si el encabezado no está presente, se proporciona una respuesta completa desde la memoria caché si la fecha de respuesta almacenada en caché es más If-None-Match reciente que el valor proporcionado. De lo contrario, se sirve una respuesta 304 - No modificado.
Date Al servir desde la memoria caché, el middleware establece el encabezado si no se proporcionó Date en la respuesta original.
Content-Length Al servir desde la memoria caché, el middleware establece el encabezado si no se proporcionó Content-Length en la respuesta original.
Age Se Age omite el encabezado enviado en la respuesta original. El middleware calcula un nuevo valor al atender una respuesta almacenada en caché.

El almacenamiento en caché respeta las directivas Cache-Control solicitudes

El middleware respeta las reglas de la especificación de almacenamiento en caché HTTP 1.1. Las reglas requieren una memoria caché para respetar un encabezado Cache-Control válido enviado por el cliente. En la especificación , un cliente puede realizar solicitudes con un valor de encabezado y forzar al servidor a generar una no-cache nueva respuesta para cada solicitud. Actualmente, no hay ningún control del desarrollador sobre este comportamiento de almacenamiento en caché cuando se usa el middleware porque el middleware se adhiere a la especificación de almacenamiento en caché oficial.

Para obtener más control sobre el comportamiento del almacenamiento en caché, explore otras características de almacenamiento en caché de ASP.NET Core. Vea los siguientes temas:

Solución de problemas

Si el comportamiento del almacenamiento en caché no es el esperado, confirme que las respuestas se pueden almacenar en caché y pueden servirse desde la memoria caché. Examine los encabezados entrantes de la solicitud y los encabezados salientes de la respuesta. Habilite el registro para ayudar con la depuración.

Al probar y solucionar problemas de comportamiento del almacenamiento en caché, un explorador puede establecer encabezados de solicitud que afectan al almacenamiento en caché de maneras no deseadas. Por ejemplo, un explorador puede establecer el Cache-Control encabezado en o al actualizar una no-cache max-age=0 página. Las herramientas siguientes pueden establecer explícitamente encabezados de solicitud y son preferibles para probar el almacenamiento en caché:

Condiciones para el almacenamiento en caché

  • La solicitud debe dar lugar a una respuesta de servidor con un código de estado 200 (correcto).
  • El método de solicitud debe ser GET o HEAD.
  • En Startup.Configure , el middleware de almacenamiento en caché de respuestas debe colocarse antes que el middleware que requiere almacenamiento en caché. Para obtener más información, vea Middleware de ASP.NET Core.
  • El Authorization encabezado no debe estar presente.
  • Cache-Control Los parámetros de encabezado deben ser válidos y la respuesta debe marcarse public y no marcarse private como .
  • El encabezado no debe estar presente si el encabezado no está presente, ya que el Pragma: no-cache encabezado invalida el encabezado cuando está Cache-Control Cache-Control Pragma presente.
  • El Set-Cookie encabezado no debe estar presente.
  • Vary Los parámetros de encabezado deben ser válidos y no iguales a * .
  • El Content-Length valor de encabezado (si se establece) debe coincidir con el tamaño del cuerpo de la respuesta.
  • No IHttpSendFileFeature se usa .
  • La respuesta no debe estar obsoleta tal como se especifica en el Expires encabezado y las directivas de caché y max-age s-maxage .
  • El almacenamiento en búfer de respuesta debe ser correcto. El tamaño de la respuesta debe ser menor que el valor configurado o SizeLimit predeterminado. El tamaño del cuerpo de la respuesta debe ser menor que el valor configurado o MaximumBodySize predeterminado.
  • La respuesta debe ser almacenable en caché según las especificaciones de RFC 7234. Por ejemplo, la no-store directiva no debe existir en los campos de encabezado de solicitud o respuesta. Consulte Sección 3: Almacenamiento de respuestas en cachés de RFC 7234 para obtener más información.

Nota

El sistema Antiforgery para generar tokens seguros para evitar ataques de falsificación de solicitud entre sitios (CSRF) establece los encabezados y en para que las respuestas no se almacenen en Cache-Control Pragma no-cache caché. Para obtener información sobre cómo deshabilitar tokens antiforgery para elementos de formulario HTML, vea Evitar ataques de falsificación de solicitud entre sitios (XSRF/CSRF) en ASP.NET Core .

Recursos adicionales