You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP.NET中间件中最佳添加Last-Modified响应头?

在ASP.NET API中添加Last-Modified响应头的实现方案与最佳实践

核心结论

完全可以在ASP.NET API响应中添加Last-Modified头,这是HTTP缓存优化的标准手段,能有效减少重复请求、降低服务器负载与带宽消耗。

实现方案

你尝试的中间件OnStarting事件触发时机较晚,此时响应内容已开始序列化到流中,无法直接获取原始返回对象,因此更推荐以下两种可靠方案:

方式一:控制器内直接设置(简单场景)

在Action返回结果前,直接通过HttpContext.Response.Headers设置头,适合单个Action的快速实现:

[HttpGet]
[Route("system/resources/{lcid}")]
[ProducesResponseType(StatusCodes.Status200OK)]        
public async Task<IResult> Get(int lcid, CancellationToken token)
{            
    var resources = await _resourceManager.GetResourcesAsync(lcid, token).ConfigureAwait(false);

    if (resources?.Items?.Any() ?? false)
    {                
        // 按HTTP标准格式(RFC 1123)设置Last-Modified值
        HttpContext.Response.Headers.Append("Last-Modified", resources.LastModified.ToString("R"));
        return Results.Ok(resources);
    }
    else
    {
        return Results.NotFound();
    }
}

方式二:自定义结果过滤器(全局复用场景)

如果多个Action都需要设置该头,推荐实现异步结果过滤器,统一处理所有实现特定接口的返回对象:

1. 定义包含LastModified属性的接口

public interface IHasLastModified
{
    DateTimeOffset LastModified { get; }
}

2. 让返回对象实现该接口

// 假设你的Resources类实现接口
public class Resources : IHasLastModified
{
    public IEnumerable<ResourceItem> Items { get; set; }
    public DateTimeOffset LastModified { get; set; }
}

3. 实现异步结果过滤器

public class LastModifiedHeaderFilter : IAsyncResultFilter
{
    public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        // 检查结果是否为ObjectResult,且值实现了IHasLastModified接口
        if (context.Result is ObjectResult objectResult && objectResult.Value is IHasLastModified hasLastModified)
        {
            // 设置符合HTTP标准的Last-Modified头
            context.HttpContext.Response.Headers.Append(
                "Last-Modified", 
                hasLastModified.LastModified.ToString("R")
            );
        }

        // 继续执行后续响应流程
        await next();
    }
}

4. 注册过滤器

  • 全局注册(Program.cs,对所有控制器生效):
builder.Services.AddControllers(options =>
{
    options.Filters.Add<LastModifiedHeaderFilter>();
});
  • 局部注册(仅对特定控制器/Action生效):
[ServiceFilter(typeof(LastModifiedHeaderFilter))]
public class ResourceController : ControllerBase
{
    // 控制器逻辑...
}

最佳实践

  • 严格遵循HTTP格式:Last-Modified的日期必须使用RFC 1123格式(通过ToString("R")生成),否则客户端缓存逻辑可能失效。
  • 配合ETag使用:Last-Modified可与ETag头配合,应对一秒内多次修改的场景,提供更精确的缓存验证。
  • 处理无效日期:若返回对象的LastModified为空或无效,不要设置该头,避免误导客户端缓存。
  • 搭配Cache-Control头:同时设置Cache-Control(如public, max-age=3600),明确缓存规则,最大化Last-Modified的作用。

Last-Modified头说明(翻译自Mozilla官方文档)

Last-Modified是HTTP响应头,用于标记资源最后修改的时间。客户端后续请求时可携带If-Modified-Since或If-Unmodified-Since头,向服务器验证资源状态:

  • 若资源未修改,服务器返回304 Not Modified,不返回资源内容,减少带宽消耗。
  • 若资源已修改,服务器返回200 OK和最新资源内容。

内容的提问来源于stack exchange,提问作者thomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 04:08:11