【问题标题】:Why is ASP.NET Core setting cache-control headers on error responses?为什么 ASP.NET Core 在错误响应中设置缓存控制标头?
【发布时间】:2021-08-26 06:44:58
【问题描述】:

startup.cs

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddDefaultPolicy(builder =>
            {
                builder
                    .AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader();
            });
        });
        services.AddResponseCaching();
        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseCors();
        app.UseResponseCaching();
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

TestController.cs

[ApiController]
public class TestController : ControllerBase
{
    [ResponseCache(Duration = 60)]
    [HttpGet("/fail")]
    public IActionResult Fail()
    {
        return BadRequest();
    }
}

当我点击 /fail 端点时,它按预期返回 400 状态,但由于操作方法上的 ResponseCache 属性,它具有 public,max-age=60 的 Cache-Control 标头。根据docs,

响应缓存中间件仅缓存导致 200 (OK) 状态代码的服务器响应。中间件会忽略任何其他响应,包括错误页面。

如何阻止错误响应(或任何非 200 响应)被缓存?

【问题讨论】:

  • 您引用的注释是指响应缓存中间件未缓存完整响应服务器端。 ResponseCacheFilter 作为 MVC 操作过滤器运行,在设置缓存标头时似乎没有考虑状态代码。
  • @KirkLarkin 是的,感谢您提供的信息。我最初并没有使用响应缓存中间件,我只是在尝试解决问题时添加了它。那么人们通常如何解决这个问题呢?他们只是接受浏览器会缓存任何错误响应?如果错误是暂时的,浏览器刷新可能会解决问题,但如果它正在缓存错误响应,则无法解决。

标签: asp.net asp.net-core caching asp.net-web-api cache-control


【解决方案1】:

ResponseCacheFilter (source) 是实际设置 Cache-Control 标头的操作过滤器,但它没有考虑状态代码,因此实际上不可能做到我想要的。

相反,我编写了自己的动作过滤器:

public class CacheControlAttribute : ActionFilterAttribute
{
    public int Duration { get; set; } = 0;

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        if (ResultIsSuccess(context.Result))
        {
            SetCacheControlHeaders(context.HttpContext.Response);
        }
    }

    private bool ResultIsSuccess(IActionResult result)
    {
        return result is IStatusCodeActionResult statusCodeActionResult && statusCodeActionResult.StatusCode is >= 200 and < 300;
    }

    private void SetCacheControlHeaders(HttpResponse response)
    {
        response.Headers[HeaderNames.CacheControl] = $"public,max-age={Duration}";
    }
}

你可以这样使用它:

[ApiController]
public class TestController : ControllerBase
{
    [CacheControl(Duration = 60)]
    [HttpGet("/fail")]
    public IActionResult Fail()
    {
        return BadRequest();
    }
}

它只会在成功状态码(>= 200 和 Cache-Control 标头。

此外,在任何一种情况下都不需要 app.UseResponseCaching() 中间件,因为它不控制 Cache-Control 标头;它只是读取它们(可能由ResponseCache 属性设置),并缓存可缓存的响应以实现服务器端缓存。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2018-04-29
    • 1970-01-01
    • 2012-02-06
    相关资源
    最近更新 更多