首页 > 解决方案 > ASP.NET Core Web API 检查 if-modified-since 标头不起作用,因为浏览器甚至没有提交到服务器

问题描述

我有一个控制器,它返回一个FileStreamResult. 部分处理查看“if-modified-since”标头是否小于数据库中返回的当前日期NotModified()或实际的FileStreamResult. 问题是,客户端(在本例中为 Swagger)甚至没有提交到我的服务器,因此我可以根据传入的标头检查数据库日期。我没有在Startup. 鉴于下面的代码,任何想法如何确保它提交回我的 web api 以便我可以进行数据库比较?

这是 Chrome 网络选项卡的屏幕截图。您可以看到第一个(显示为test)提交到服务器(我已禁用缓存打开),然后再次提交并由(磁盘缓存)提供服务- 从不访问服务器。

在此处输入图像描述

请注意,我将这些链接作为我的模板:

  1. https://rehansaeed.com/asp-net-core-caching-in-practice/#last-modified--if-modified-since
  2. https://www.geekytidbits.com/efficient-caching-dynamic-resources-asp-net-304-not-modified/
[ApiController]
public class DownloadSpecificVersion : ControllerBase
{
    private readonly IDbConnectionFactory dbConnectionFactory;

    public DownloadSpecificVersion( IDbConnectionFactory dbConnectionFactory ) => this.dbConnectionFactory = dbConnectionFactory;

    public record Parameters
    {
        private string _folder;
        [FromRoute]
        public string Folder
        {
            get => _folder.KatAppFolder();
            set => _folder = value;
        }

        [FromRoute]
        public string Name { get; init; }

        [FromRoute]
        public string Version { get; init; }
    }

    [HttpGet( "/api/kat-apps/{folder}/{name}/version/{version}" )]
    [SwaggerOperation(
        Summary = "Download specific version of KatApp kaml file",
        Description = "Download specific version of KatApp kaml file",
        OperationId = "KatApps.DownloadSpecificVersion",
        Tags = new[] { "KatApps" } )]
    [ProducesResponseType( typeof( FileStreamResult ), StatusCodes.Status200OK )]
    [ProducesResponseType( StatusCodes.Status304NotModified )]
    [ProducesResponseType( typeof( ValidationProblemDetails ), StatusCodes.Status401Unauthorized )]
    [ProducesResponseType( typeof( ValidationProblemDetails ), StatusCodes.Status404NotFound )]
    public async Task<IActionResult> HandleAsync( [FromQuery] Parameters parameters )
    {
        using ( var cn = await dbConnectionFactory.CreateDataLockerConnectionAsync() )
        {
            var keyInfo = await cn.QueryBuilder( $@"omitted, query to find item in db" ).QueryFirstOrDefaultAsync<CacheDownloadInfo>();

            return keyInfo != null
                ? await CachedOrModifiedAsync( keyInfo, dbConnectionFactory )
                : NotFound();
        }
    }
}

protected async Task<IActionResult> CachedOrModifiedAsync( CacheDownloadInfo cacheDownloadInfo, IDbConnectionFactory dbConnectionFactory )
{
    var lastModifiedDate = cacheDownloadInfo.LastModifiedDate.Value.ToUniversalTime();

    // https://rehansaeed.com/asp-net-core-caching-in-practice/#last-modified--if-modified-since
    // https://www.geekytidbits.com/efficient-caching-dynamic-resources-asp-net-304-not-modified/
    var requestHeaders = HttpContext.Request.GetTypedHeaders();

    // HTTP does not provide milliseconds, so remove it from the comparison
    if ( requestHeaders.IfModifiedSince.HasValue && lastModifiedDate.AddMilliseconds( -lastModifiedDate.Millisecond ) <= requestHeaders.IfModifiedSince.Value )
    {
        return NotModified();
    }

    var responseHeaders = HttpContext.Response.GetTypedHeaders();

    responseHeaders.LastModified = lastModifiedDate;

    var fs = File.OpenRead( "c:\test.txt" ); // This is really code that gets a 'stream' from the database
    return new FileStreamResult( fs, "text/plain" );
}

标签: c#asp.net-corecachingasp.net-core-webapibrowser-cache

解决方案


$.ajax()我的问题是我通过简单的调用在浏览器控制台中对此进行了测试。我需要ifModified: true在配置中设置它以使用标头调用服务器if-modified-since

我在使用 Swagger 时发现了另一个问题。如果我设置以下内容,它似乎才有效:

responseHeaders.CacheControl = new Microsoft.Net.Http.Headers.CacheControlHeaderValue
{
    Public = true,
    MustRevalidate = true,
    MaxAge = new TimeSpan( 0, 0, 0 ),
};
responseHeaders.Expires = DateTime.UtcNow;

这将导致:

Cache-Control:public, must-revalidate, max-age=0 Last-Modified:Sun, 10 Jun 2012 20:19:21 GMT


推荐阅读