如何让 IIS 从 WebApi 2 返回自定义缓存控制标头,IIS 10 每次都返回私有

问题描述

** 2021 年 1 月 27 日更新 ** 我一直在与 Microsoft 合作解决此问题,我们进行了请求跟踪并查看了 FREB 日志并确认代码输出了正确的标头,但在 END_REQUEST 处理程序中,它们被缓存控制私有替换。在从头构建几个虚拟机后,我们了解到开箱即用,这个问题不会发生。但是,当我们安装最新版本的 STACKIFY AGENT (4.29.29) 时,一旦我们将代理置于此行为上,就会发生这种情况。旧版本的 Stackify 代理(RETRACE 分析器和 APM)不会这样做,但到目前为止,这是不可逆转的:一旦我们安装 4.29.29 的 Stackify,卸载或安装旧版本并不能撤消此问题,环境在某种程度上永久修改

STACKIFY 响应了一个有效的解决方案(但建议卸载后留下一些东西):设置环境变量 STACKIFY_ENABLERUM = false .. 我们尝试了这个,IIS 返回了我们正确的标头,而没有用缓存控制:私有替换它。


我想使用 CloudFront CDN 将流量缓存到我的 API,以便将请求卸载到内容交付网络。

我正在尝试将 Cache-Control 标头设置为返回:Cache-Control: "public,max-age=10"。当我在 Visual Studio 2019 中运行我的代码进行调试时,我得到了正确的标头。但是,当我将它部署到 IIS 时,我总是返回:

缓存控制:私有

我正在运行带有 IIS 版本 10.0.17763.1 的 Windows Server 2019。我正在使用带有 Web API 2 的 ASP.NET MVC 来操作 REST API。

在我的代码中我创建了这个属性

代码

 public class CacheControlAttribute : System.Web.Http.Filters.ActionFilterattribute
    {
        public int MaxAge { get; set; }

        public CacheControlAttribute()
        {
            MaxAge = 0;
        }

        public override void OnActionExecuted(HttpActionExecutedContext context)
        {
            // Don't set the cache header if there was an error or if there was no content in the response
            if (context.Response != null && context.Response.IsSuccessstatusCode)
            {
                context.Response.Headers.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue
                {
                    Private = false,Public = true,MaxAge = TimeSpan.FromSeconds(MaxAge)
                };                

            }

            base.OnActionExecuted(context);
        }
    }

然后我用这个属性装饰我的方法

[CacheControl(MaxAge = 10)]

我阅读了几篇关于 StackOverflow 的文章,但未能解决这个问题。我也尝试将其添加到 web.config:

它没有帮助。

我在一台 IIS 服务器上成功运行了这个,IIS 版本相同,但我的代码版本较旧。我在新的 IIS 服务器上设置它时遇到问题,我认为这是 IIS 配置问题,但我不确定。也许它在我的 web.config 中。

感谢您对此的任何帮助。

解决方法

缓存控制分为请求和响应指令。我猜你说的是响应中的缓存控制,因为请求缓存控制不能在 IIS 中设置。

出于安全考虑,IIS默认会设置cache-control为private,所以你会遇到这个问题。当没有用于请求的输出缓存(并且您启用了输出缓存)时,这是 .NET 的默认行为。如果您在 web.config 中将 sendCacheControlHeader 设置为 false,您将不会获得 Cache-Control: 私有标头。

所以一个简单的方法是设置 sendCacheControlHeader false 并添加缓存控件将删除私有。您也不需要在 MVC 中自定义缓存控制过滤器。

<system.web>
   <httpRuntime sendCacheControlHeader="false" /> 
</system.web>

<httpProtocol>
 <customHeaders>
   <remove name="X-Powered-By" />
    <add name="Cache-Control" value="max-age=30,public" />
 </customHeaders>
</httpProtocol>

另一个想法是为每个动作或控制器添加缓存输出。 .NET 有一个定义的过滤器来控制 maxage,你不需要自己定义它。您可以使用 [OutputCache(Duration = 0)]

OutputCache

,

你需要像这样在现有的输出缓存之上实现你自己的

public static class MyCustomCacheConfig
{
    public static int Duration = 600; //whatever time you want
}

public class CdnCacheCacheAttribute : OutputCacheAttribute
{
    public CdnCacheCacheAttribute()
    {
        this.Duration = MyCustomCacheConfig.Duration;
    }
}

[CdnCacheCacheAttribute(Duration = 100,VaryByParam = "none")]
public ActionResult YourActions()
{
    return View();
}

VaryByParm 在 Microsoft 的输出缓存中。它控制 HttpCaching

// Get the current VaryByParam.
String varyByParamValue =  outputCacheProfile.VaryByParam;

// Set the VaryByParam.outputCacheProfile.VaryByParam = string.Empty;