6

有没有一种方法可以使用 ASP.NET 以编程方式在代码中设置 Expires 标头?具体来说,我需要在整个文件夹和所有子文件夹上设置它,并且该文件夹仅包含静态文件(JavaScript、CSS、图像等)而不包含 aspx 文件,所以我不能只在 aspx 代码中添加一些代码-page_load 后面。

我通常可以直接在 IIS 中设置它。但是服务器被客户端锁定(我只能通过 FTP 访问 Web 应用程序目录以进行部署),并且让客户端在 IIS 上设置 Expires 标头需要一个冰河时代(它是一个公共部门/政府站点)。

根据雅虎的建议,我这样做是出于前端优化的原因http://developer.yahoo.com/performance/rules.html#expires

更新:我试过创建一个 HttpModule ......

public class FarFutureExpiresModule : IHttpModule
{
    public void Dispose() { }

    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(context_BeginRequest);
    }

    void context_BeginRequest(object sender, EventArgs e)
    {
        HttpContext context = HttpContext.Current;

        string url = context.Request.Url.ToString();

        if (url.Contains("/StaticContent/"))
        {
            context.Response.Cache.SetExpires(DateTime.Now.AddYears(30));
        }
    }
}

虽然这看起来行不通。我在代码上放置了一个断点,它可以正常运行。但是,当我在 Firefox 中分析原始 HTTP 标头信息时,没有设置 expires 值。请注意,我正在使用 BeginRequest,但我也尝试过连接 PostReleaseRequestState 和 PreSendRequestHeaders,但它们似乎也不起作用。有任何想法吗?

更新 2:好的,因为我正在运行 IIS6,HttpModules 不会运行静态文件,只能运行动态文件(*.aspx 等)。感谢 RickNZ 的帮助,我想出了以下 IHttpModule:

public class FarFutureExpiresModule : IHttpModule
{
    public void Dispose() { }

    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(context_BeginRequest);
    }

    void context_BeginRequest(object sender, EventArgs e)
    {
        HttpContext context = HttpContext.Current;

        string url = context.Request.Url.ToString();

        if (url.Contains("/StaticContent/"))
        {
            context.Response.Cache.SetExpires(DateTime.Now.AddYears(30));
            context.Response.Cache.SetMaxAge(TimeSpan.FromDays(365.0 * 3.0));
        }
    }
}

...而且它似乎有效,但仅在 Visual Studio 的内置 Web 服务器和 IIS7 中(在集成管道模式下)。一位工作同事提到在 IIS6 上设置通配符映射以让 HttpModules 处理静态文件,但如果我可以访问 IIS6,我可以直接设置 Far-Future Expires 标头,而不用打扰这个 HttpModule。那好吧!

4

3 回答 3

3

如果您使用的是 IIS 7,最简单的方法是编写一个 HttpModule 以在集成模式下为静态文件运行,并从那里设置 Expires 和 Cache-Control 标头。

更新:

您的 HttpModule 应该可以工作,尽管我通常也会调用:

context.Response.Cache.SetMaxAge(TimeSpan.FromDays(365.));

更新 2:

使用 IIS 6,您必须以编程方式修改元数据库。这是可能的,尽管它需要提升的权限。

唯一的其他选择是用 C++ 编写 ISAPI 模块。

于 2009-12-18T11:53:28.503 回答
1

即使 YSLOW 提出了建议,您也可以从阅读 Atwood 先生的文章中受益:YSlow:雅虎的问题不是您的问题

来自文章:

添加过期标题(权重:11)

这本身并不是一个坏建议,但如果你弄错了,它可能会导致巨大的问题。例如,在 Microsoft 的 IIS 中,Expires 标头在默认情况下始终处于关闭状态,可能正是出于这个原因。通过在 HTTP 资源上设置 Expires 标头,您是在告诉客户端永远不要检查该资源的新版本——至少在 Expires 标头的到期日期之前不要检查。当我说从不时,我是认真的——浏览器甚至不会要求新版本;它只是假设它的缓存版本很好,直到客户端清除缓存,或者缓存达到到期日期。雅虎指出,当他们需要刷新这些资源时,他们会更改这些资源的文件名。

所以我想其中一个要点是:假设您更改了主 css 文件的内容,但您没有同时重命名 css 文件。如果您接受 Yahoo 的建议,您的最终用户将在标头的到期日期之前获得您编辑的文件的更新版本。你对这样的场景感到满意吗?

于 2011-08-01T19:07:50.173 回答
0

提高性能的好方法包括:gzip 压缩响应(在 IIS6 中不是最简单的)、缩小静态文件(css、js)、将静态文件合并在一起(一个大 css、一个大 js)、使用 sprite。这个想法是减少 HTTP 请求的总数,然后减少响应的大小。

于 2009-12-18T12:40:43.170 回答