关于利用浏览器缓存有几个问题,但我没有发现任何有用的方法来在ASP中实现这一点.NET应用程序.谷歌的Pagespeed告诉我们这是性能最大的问题.

<system.webServer>
  <staticContent>
    <!--<clientCache cacheControlMode="UseExpires"
            httpExpires="Fri, 24 Jan 2014 03:14:07 GMT" /> -->
    <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.24:00:00" />
  </staticContent>
</system.webServer>

注释代码有效.我可以将expire header设置为将来某个特定的时间,但无法将cacheControlMaxAge设置为从现在开始缓存静态内容的天数.它不起作用.我的问题是:

我该怎么做?

在Web配置中设置此代码后,我得到72页的速度(之前是71页).50个文件未缓存.(现在49岁)我想知道为什么,我刚刚意识到实际上缓存了一个文件(SVG文件).不幸的是,png和jpg文件不是. 这是我的web.config美元

<?xml version="1.0" encoding="utf-8"?>

<configuration>
  <configSections>
    <section name="exceptionManagement" type="Microsoft.ApplicationBlocks.ExceptionManagement.ExceptionManagerSectionHandler,Microsoft.ApplicationBlocks.ExceptionManagement" />
    <section name="jsonSerialization"     type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions,   Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E34" requirePermission="false" allowDefinition="Everywhere" />
    <sectionGroup name="elmah">
      <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah"    />
      <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah"    />
      <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
      <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
    </sectionGroup>
  </configSections>

  <exceptionManagement mode="off">
    <publisher mode="off" assembly="Exception"  type="blabla.ExceptionHandler.ExceptionDBPublisher"  connString="server=188......;database=blabla;uid=blabla;pwd=blabla; " />
  </exceptionManagement>
  <location path="." inheritInChildApplications="false">
    <system.web>
      <httpHandlers>
        <add verb="GET,HEAD" path="ScriptResource.axd"  type="System.Web.Handlers.ScriptResourceHandler,System.Web.Extensions, Version=1.0.61025.0,  Culture=neutral, PublicKeyToken=31bf3856ad364e34" validate="false" />
        <add verb="GET" path="Image.ashx" type="blabla.WebComponents.ImageHandler, blabla/>"
        <add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory" />
        <add verb="*" path="*.jpg" type="System.Web.StaticFileHandler" />
        <add verb="GET" path="*.js" type="System.Web.StaticFileHandler" />
        <add verb="*" path="*.gif" type="System.Web.StaticFileHandler" />
        <add verb="GET" path="*.css" type="System.Web.StaticFileHandler" />
      </httpHandlers>
      <compilation defaultLanguage="c#" targetFramework="4.5.1" />
      <trace enabled="false" requestLimit="100" pageOutput="true" traceMode="SortByTime" localOnly="true"/>
      <authentication mode="Forms">
        <forms loginUrl="~/user/login.aspx">
          <credentials passwordFormat="Clear">
            <user name="blabla" password="blabla" />
          </credentials>
        </forms>
      </authentication>
      <authorization>
        <allow users="*" />
      </authorization>
      <sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" cookieless="false" timeout="20" />
      <globalization requestEncoding="utf-8" responseEncoding="utf-8" culture="en-GB" uiCulture="en-GB" />
      <xhtmlConformance mode="Transitional" />
      <pages controlRenderingCompatibilityVersion="4.5" clientIDMode="AutoID">
        <namespaces>

        </namespaces>
        <controls>
          <add assembly="Microsoft.AspNet.Web.Optimization.WebForms" namespace="Microsoft.AspNet.Web.Optimization.WebForms" tagPrefix="webopt" />
        </controls>
      </pages>
      <webServices>
        <protocols>
          <add name="HttpGet" />
          <add name="HttpPost" />
        </protocols>
      </webServices>
    </system.web>
  </location>
  <appSettings>

  </appSettings>
  <connectionStrings>

  </connectionStrings>
  <system.web.extensions>
    <scripting>
      <webServices>
        <jsonSerialization maxJsonLength="200000" />
      </webServices>
    </scripting>
  </system.web.extensions>
  <startup>
    <supportedRuntime version="v2.0.50727" />
    <supportedRuntime version="v1.1.4122" />
    <supportedRuntime version="v1.0.3705" />
  </startup>
  <system.webServer>


    <rewrite>
      <providers>
        <provider name="ReplacingProvider" type="ReplacingProvider, ReplacingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5ab632b1f332b247">
          <settings>
            <add key="OldChar" value="_" />
            <add key="NewChar" value="-" />
          </settings>
        </provider>
        <provider name="FileMap" type="DbProvider, Microsoft.Web.Iis.Rewrite.Providers, Version=7.1.761.0, Culture=neutral, PublicKeyToken=0525b0627da60a5e">
          <settings>
            <add key="ConnectionString" value="server=;database=blabla;uid=blabla;pwd=blabla;App=blabla"/>
            <add key="StoredProcedure" value="Search.GetRewriteUrl"/>
            <add key="CacheMinutesInterval" value="0"/>
          </settings>
        </provider>
      </providers>
      <rewriteMaps configSource="rewritemaps.config" />
      <rules configSource="rewriterules.config" />
    </rewrite>
    <modules>
      <remove name="ScriptModule" />
      <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3456AD264E35" />
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
    </modules>
    <handlers>
      <add name="Web-JPG" path="*.jpg" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
      <add name="Web-CSS" path="*.css" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
      <add name="Web-GIF" path="*.gif" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
      <add name="Web-JS" path="*.js" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
    </handlers>
    <validation validateIntegratedModeConfiguration="false" />
    <httpErrors errorMode="DetailedLocalOnly" existingResponse="Auto">
      <remove statusCode="404" subStatusCode="-1"/>
      <remove statusCode="500" subStatusCode="-1"/>
      <error statusCode="404" path="error404.htm" responseMode="File"/>
      <error statusCode="500" path="error.htm" responseMode="File"/>
    </httpErrors>
  </system.webServer>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="soapBinding_AdriagateService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true" messageEncoding="Text">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
          <security mode="None" />
        </binding>
      </basicHttpBinding>
      <netTcpBinding>
        <binding name="NetTcpBinding_ITravellerService" closeTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
          <security mode="None" />
        </binding>
      </netTcpBinding>
    </bindings>
    <client>
      <endpoint address="blabla" bindingConfiguration="soapBinding_blabla" contract="" Address="blabla" name="blabla" />
        <endpoint address="blabla" binding="basicHttpBinding" bindingConfiguration="soapBinding_IImagesService"
          contract="ImagesService.IImagesService" name="soapBinding_IImagesService"/>
        <identity>
          <servicePrincipalName value="blabla"/>
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.5.0.0" newVersion="4.5.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.web>
    <httpModules>
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
    </httpModules>
  </system.web>
  <elmah>
    <security allowRemoteAccess="false" />
  </elmah>
  <location path="elmah.axd" inheritInChildApplications="false">
    <system.web>
      <httpHandlers>
        <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
      </httpHandlers>

    </system.web>
    <system.webServer>
      <handlers>
        <add name="ELMAH" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
      </handlers>
    </system.webServer>
  </location>
</configuration>

EDIT:个 如果我设置了确切的到期日期,则缓存可以工作,但不适用于jpg、gif……仅适用于png.

EDIT2:

<clientCache cacheControlCustom="public" 
cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" /> 

缓存正在工作,但是still不适用于jpeg和gif;它只适用于svg和png.

推荐答案

大多数浏览器缓存问题都可以通过查看响应标题来解决(可以在Google chrome开发者工具中完成).

在此处输入图像描述

现在,您的web.config文件的clientCache部分应该将您的输出缓存设置为最大年龄,正如您在下图中看到的那样,已经将max-age设置为86400,即1天(以秒为单位).

这里是网络.此设置的配置代码段.

<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="1.00:00:00" />

这很好,响应头在Cache-Control头上设置了max-age属性.因此浏览器可能会缓存内容.这基本上是正确的,但有些浏览器需要设置另一个标志.特别是为缓存控制头设置的public标志.这可以通过使用web.config中的cacheControlCustom属性轻松添加.下面是一个例子.

<clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="1.00:00:00" />

现在,当我们重试页面并判断标题时.

在此处输入图像描述

正如你从上图中看到的,我们现在得到了public, max-age=86400.因此,我们的浏览器拥有缓存资源所需的一切.现在,判断谷歌浏览器的标题和网络标签将对我们有所帮助.

这是对该文件的第一个请求.请注意,该文件未缓存. 在此处输入图像描述

现在,让我们回到这个页面(NOTE:不刷新页面,我们将在一秒钟内讨论).您将在now returning from cache中看到响应(如圆圈所示).

在此处输入图像描述

现在,如果我使用F5或使用浏览器刷新功能刷新页面,会发生什么情况.等等...那(from cache)块go 哪儿了. 在此处输入图像描述

嗯,在Google Chrome中(其他浏览器不确定),使用刷新按钮将重新下载静电资源,而不管缓存头是什么.这意味着已经重新检索了资源,并且发送了最大年龄标头.

现在,在完成以上所有解释之后,确保测试how您正在监视缓存头.

Update

根据您的 comments ,您声明有一个名为Image.ashx的通用处理程序(IHttpHandler),其内容类型为image/jpg.现在,您可能期望默认行为是缓存这个处理程序.然而,IIS将扩展.ashx(正确地)视为一个动态脚本,并且在没有在代码本身中显式设置缓存头的情况下不受缓存的约束.

这就是您需要小心的地方,因为通常IHttpHandlers个实际上不应该被缓存,因为它们通常提供动态内容.现在,如果该内容不太可能更改,您可以直接在代码中设置缓存头.下面是使用Response上下文在IHttpHandlers中设置缓存头的示例.

context.Response.ContentType = "image/jpg";

context.Response.Cache.SetMaxAge(TimeSpan.FromDays(1));
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetSlidingExpiration(true);

context.Response.TransmitFile(context.Server.MapPath("~/out.jpg"));

现在看看代码,我们在Cache属性上设置了一些属性.为了得到想要的响应,我设置了属性.

  • context.Response.Cache.SetMaxAge(TimeSpan.FromDays(1));告诉输出缓存将Cache-Control报头的max-age=部分设置为future 1天(86400秒).
  • context.Response.Cache.SetCacheability(HttpCacheability.Public);告诉输出缓存将Cache-Control头设置为public.这非常重要,因为它告诉浏览器缓存到对象.
  • context.Response.Cache.SetSlidingExpiration(true);告诉输出缓存确保正确设置Cache-Control报头的max-age=部分.在不设置滑动过期的情况下,IIS out-put缓存将忽略最大年龄头.把这些放在一起,我得到了这个结果.

ashx文件的输出缓存

如上所述,您可能不想缓存这.ashx个文件,因为它们通常提供动态内容.但是,如果动态内容在给定的时间段内不太可能发生变化,您可以使用上述方法交付.ashx个文件.

现在,结合上面列出的流程,您还可以设置缓存头的100(请参阅wiki)组件,以便浏览器可以验证由自定义字符串传递的内容.维基声明:

ETag是由web服务器分配给特定用户的不透明标识符

因此,对于浏览器来说,这实际上是一种唯一的标识,用于标识响应中传递的内容.通过提供该标头,浏览器在下一次重新加载时将发送If-None-Match标头和来自上次响应的ETag.我们可以修改我们的处理程序来检测If-None-Match头,并将其与我们自己生成的Etag进行比较.现在没有精确的科学来生成ETags,但是一个很好的经验法则是提供一个最有可能只定义一个实体的标识符.在本例中,我喜欢使用连接在一起的两个字符串,例如.

System.IO.FileInfo file = new System.IO.FileInfo(context.Server.MapPath("~/saveNew.png"));
string eTag = file.Name.GetHashCode().ToString() + file.LastWriteTimeUtc.Ticks.GetHashCode().ToString();

在上面的代码片段中,我们正在从文件系统加载一个文件(您可以从任何地方获得).然后,我使用GetHashCode()方法(对所有对象)来获取对象的整数哈希代码.在本例中,我先计算文件名的哈希值,然后是最后一次写入日期.最后写入日期的原因是,如果文件发生更改,哈希代码也会发生更改,从而使finger prints不同.

这将生成一个类似于306894467-210133036的哈希代码.

那么我们如何在处理程序中使用它呢.下面是该处理程序的最新修改版本.

System.IO.FileInfo file = new System.IO.FileInfo(context.Server.MapPath("~/out.png"));
string eTag = file.Name.GetHashCode().ToString() + file.LastWriteTimeUtc.Ticks.GetHashCode().ToString();
var browserETag = context.Request.Headers["If-None-Match"];

context.Response.ClearHeaders();
if(browserETag == eTag)
{
    context.Response.Status = "304 Not Modified";
    context.Response.End();
    return;
}
context.Response.ContentType = "image/jpg";
context.Response.Cache.SetMaxAge(TimeSpan.FromDays(1));
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetSlidingExpiration(true);
context.Response.Cache.SetETag(eTag);
context.Response.TransmitFile(file.FullName);

如您所见,我对处理程序做了很大的更改,但是您会注意到,我们生成了Etag哈希,判断传入的If-None-Match报头.如果ETag散列和报头相等,那么我们通过返回状态代码304 Not Modified来告诉浏览器内容没有改变.

接下来是相同的处理程序,除了我们通过调用添加ETag头:

context.Response.Cache.SetETag(eTag);

当我们在浏览器中运行它时,我们会得到.

带ETag的缓存控制

您将从图像中看到(正如我更改了文件名一样),我们现在已经将缓存系统的所有组件安装到位.ETag作为头文件发送,浏览器发送请求头If-None-Match,这样我们的处理程序就可以相应地响应缓存文件的更改.

Asp.net相关问答推荐

AJAX返回未定义、失败

在 Web.Config 中模拟标签

如何以编程方式设置单元格 colored颜色 epplus?

使用 Owin 身份验证的服务器端声明缓存

如何判断 IIS 是处于 32 位还是 64 位模式

使用 jQuery.ajax() 时如何处理错误?

如何检测 ASP.net 应用程序中的 SqlServer 连接泄漏?

无法加载文件或程序集'System.Web.WebPages.Razor,版本 = 3.0.0.0

部署后网站需要强制刷新

Web Api 参数始终为空

使用 LINQ 进行递归控制搜索

存在 ios 7 虚拟键盘时,div 元素不会停留在底部

aspnet_compiler 发现错误版本的 System.Web.WebPages 1.0.0.0 而不是 2.0.0.0

如何避免 ASP.NET MVC 中的 HttpRequestValidationException 呈现导致异常的相同视图

如何在 ASP.Net Gridview 中添加确认删除选项?

头标记中的内联代码 - ASP.NET

StyleBundle 索引超出了数组的范围

在 Asp.Net MVC 5 中获取登录用户的用户 ID

您的下一个 ASP.NET 项目的 Select 是什么:Web 窗体还是 MVC?

如何使用实体框架执行原始 SQL 查询而无需使用模型?