IIS 7返回304而不是200


10

我对IIS 7有一个奇怪的问题。
有时它似乎返回304而不是200。

这是Fiddler捕获的一个示例请求:(
请注意,请求的文件尚未位于我的浏览器缓存中。)

GET https://[mysite]/Content/js/jquery.form.js HTTP/1.1
Accept: */*
Referer: https://[mysite]/Welcome/News
Accept-Language: sv-SE
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; OfficeLiveConnector.1.4; OfficeLivePatch.1.3; .NET4.0C; .NET4.0E)
Accept-Encoding: gzip, deflate
Host: [mysite]
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: ...

请注意,请求中没有If-Modified-Since或If-None-Match。
但仍然是:

HTTP/1.1 304 Not Modified
Cache-Control: public
Expires: Tue, 02 Mar 2010 06:26:08 GMT
Last-Modified: Mon, 22 Feb 2010 21:58:44 GMT
ETag: "1CAB40A337D4200"
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Mon, 01 Mar 2010 17:06:34 GMT

有谁知道这里可能出什么问题了吗?

我正在Windows Web Server 2008 R2上运行IIS 7。

编辑:

我找到了一种解决方法,启用缓存,然后在扩展级别上将其禁用,这为我解决了问题。

<configuration>
  <system.webServer>
    <caching enabled="true" enableKernelCache="true">
      <profiles>
        <add extension=".png" policy="DisableCache" kernelCachePolicy="DisableCache" />
        <add extension=".gif" policy="DisableCache" kernelCachePolicy="DisableCache" />
        <add extension=".js" policy="DisableCache" kernelCachePolicy="DisableCache" />
        <add extension=".css" policy="DisableCache" kernelCachePolicy="DisableCache" />
      </profiles>
    </caching>
    <staticContent>
      <clientCache cacheControlMode="NoControl" />
    </staticContent>
  </system.webServer>
</configuration>

我遇到了完全相同的问题,并且在非常繁忙的Web服务器上引起了很多问题。即使客户端还没有资源副本,IIS也会返回304。
Philippe Leybaert

@Philippe,您找到解决方案了吗?否则,请参阅上方的我的编辑以找到一种解决方法,并在下面签出新答案。
Ola Herrdahl 2010年

@OlaHerrdahl,您的解决方法很完美:)我也遇到了这个确切的问题。谢谢!
阿迪·阿拉姆

Answers:


3

根据HTTP1.1规范的14.9节no-cache仅源服务器不能使用Cache-Control标头的指令,这意味着IIS忽略了请求中的标头。

缓存控制指令可以分为以下常规类别:

  - Restrictions on what are cacheable; these may only be imposed

由原始服务器。

14.9.1节定义publicprivateno-cache作为限制可缓存内容(只能由服务器强加)的指令。

如果您不希望缓存.js文件,则需要no-cache在应用程序中设置指令(即​​ASP.NET代码),或者需要Cache-Control在请求中更改标头以使用no-store指令代替no-cache

编辑:
根据您的评论-是的,我认为您不希望文件被缓存。然后,可能由于文件位于IIS的内部缓存之一中而导致出现304。看看这些:


我认为您在这里误解了我的问题。该文件尚未位于我的缓存中。但是,服务器仍然会回复304 ...在所有主要浏览器中浏览网站时,这似乎是随机发生的。
Ola Herrdahl'3

@Ola Herrdahl:看看我的编辑。
squillman 2010年

我也尝试禁用IIS中的缓存,这没有什么区别... :(
Ola Herrdahl 2010年

1

一段时间以来,我一直遇到相同的问题,并且所有缓存都已关闭...但是,我在某个时候为IIS7安装了Compression模块,默认情况下,该模块已在现有站点上启用了静态文件的压缩。我已关闭了受影响站点的所有压缩功能,现在它们似乎可以很好地处理木材


1

我们也遇到了这个错误,但是我们使用的是资产管理库(Cassette)。在对该问题进行广泛调查之后,我们发现此问题的根本原因是ASP.NET,IIS和Cassette的组合。我不确定这是否是您的问题(使用HeadersAPI而不是CacheAPI),但是模式似乎相同。

错误#1

盒式磁带将Vary: Accept-Encoding标头设置为对包的响应的一部分,因为它可以使用gzip / deflate编码内容:

但是,ASP.NET输出缓存将始终返回首先缓存的响应。例如,如果第一个请求Accept-Encoding: gzip满足,并且Cassette返回压缩的内容,则ASP.NET输出缓存将URL缓存为Content-Encoding: gzip。对相同URL但具有不同可接受编码(例如Accept-Encoding: deflate)的下一个请求将使用返回缓存的响应Content-Encoding: gzip

此错误是由Cassette使用HttpResponseBase.CacheAPI设置输出缓存设置(例如Cache-Control: public)但使用HttpResponseBase.HeadersAPI设置Vary: Accept-Encoding标头引起的。问题是,ASP.NET OutputCacheModule知道响应头的; 它仅通过CacheAPI 起作用。也就是说,它期望开发人员使用不可见的紧密耦合的API,而不仅仅是标准的HTTP。

错误#2

使用IIS 7.5(Windows Server 2008 R2)时,错误1可导致IIS内核和用户缓存单独出现问题。例如,一旦成功使用捆绑包进行缓存Content-Encoding: gzip,就可以在IIS内核缓存中看到捆绑包netsh http show cachestate。它显示带有200状态代码和内容编码为“ gzip”的响应。如果下一个请求具有不同的可接受的编码(例如 Accept-Encoding: deflate一个If-None-Match使束的散列相匹配头,进入IIS的内核和用户模式高速缓存中的请求将被认为是未命中。因此,导致请求由Cassette处理,并返回304:

但是,一旦IIS的内核和用户模式处理了响应,他们将看到URL的响应已更改并且应该更新缓存。如果netsh http show cachestate再次检查IIS内核缓存,则将缓存的200响应替换为304响应。捆绑包的所有后续请求,无论Accept-EncodingIf-None-Match都会返回304响应。我们看到了此错误的毁灭性影响,因为随机请求有意外的Accept-Encoding和,为所有用户的核心脚本提供了304的服务If-None-Match

问题似乎是IIS内核和用户模式缓存不能根据Accept-Encoding标头而变化。作为证明,通过将CacheAPI与下面的解决方法结合使用,似乎总是会跳过IIS内核和用户模式缓存(仅使用ASP.NET输出缓存)。可以通过netsh http show cachestate使用以下解决方法检查是否为空来确认这一点。ASP.NET直接与IIS工作人员通信,以根据请求有选择地启用或禁用IIS内核和用户模式缓存。

我们无法在较新版本的IIS(例如IIS Express 10)上重现此错误。但是,错误1仍可重现。

我们对该漏洞的原始修复是仅对像其他提到的Cassette请求禁用IIS内核/用户模式缓存。通过这样做,我们在Web服务器之前部署了额外的缓存层时发现了错误#1。查询字符串被破解的原因是,OutputCacheModule如果Cache未使用API​​根据QueryString 进行更改,并且请求包含QueryString则会记录缓存丢失

解决方法

我们一直在计划离开Cassette,因此与其选择维护自己的Cassette分支(或尝试合并PR),不如选择使用HTTP模块来解决此问题。

public class FixCassetteContentEncodingOutputCacheBugModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.PostRequestHandlerExecute += Context_PostRequestHandlerExecute;
    }

    private void Context_PostRequestHandlerExecute(object sender, EventArgs e)
    {
        var httpContext = HttpContext.Current;

        if (httpContext == null)
        {
            return;
        }

        var request = httpContext.Request;
        var response = httpContext.Response;

        if (request.HttpMethod != "GET")
        {
            return;
        }

        var path = request.Path;

        if (!path.StartsWith("/cassette.axd", StringComparison.InvariantCultureIgnoreCase))
        {
            return;
        }

        if (response.Headers["Vary"] == "Accept-Encoding")
        {
            httpContext.Response.Cache.VaryByHeaders.SetHeaders(new[] { "Accept-Encoding" });
        }
    }

    public void Dispose()
    {

    }
}

我希望这可以帮助某人helps!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.